Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.golangci.yml2
-rw-r--r--CHANGELOG.md4
-rw-r--r--client/dial.go4
-rw-r--r--client/sidechannel.go6
-rw-r--r--cmd/gitaly-git2go/featureflags.go2
-rw-r--r--cmd/gitaly-git2go/main.go2
-rw-r--r--cmd/gitaly-hooks/hooks.go2
-rw-r--r--cmd/gitaly-hooks/hooks_test.go10
-rw-r--r--cmd/gitaly-ssh/main.go2
-rw-r--r--doc/PROCESS.md2
-rw-r--r--doc/protobuf.md5
-rw-r--r--go.mod12
-rw-r--r--go.sum23
-rw-r--r--internal/backup/backup.go7
-rw-r--r--internal/backup/repository.go2
-rw-r--r--internal/cache/diskcache_test.go2
-rw-r--r--internal/cache/keyer.go2
-rw-r--r--internal/cli/error.go12
-rw-r--r--internal/cli/gitaly/serve.go4
-rw-r--r--internal/cli/praefect/main.go15
-rw-r--r--internal/cli/praefect/serve.go4
-rw-r--r--internal/cli/praefect/subcmd.go4
-rw-r--r--internal/cli/praefect/subcmd_metadata.go123
-rw-r--r--internal/cli/praefect/subcmd_metadata_test.go53
-rw-r--r--internal/cli/praefect/subcmd_sql_migrate.go80
-rw-r--r--internal/cli/praefect/subcmd_sql_migrate_test.go46
-rw-r--r--internal/cli/praefect/subcmd_track_repository.go119
-rw-r--r--internal/cli/praefect/subcmd_track_repository_test.go292
-rw-r--r--internal/cli/praefect/subcmd_verify.go93
-rw-r--r--internal/cli/praefect/subcmd_verify_test.go41
-rw-r--r--internal/command/command.go2
-rw-r--r--internal/command/command_test.go17
-rw-r--r--internal/command/spawntoken.go27
-rw-r--r--internal/command/spawntoken_test.go45
-rw-r--r--internal/featureflag/context.go (renamed from internal/metadata/featureflag/context.go)0
-rw-r--r--internal/featureflag/context_test.go (renamed from internal/metadata/featureflag/context_test.go)2
-rw-r--r--internal/featureflag/featureflag.go (renamed from internal/metadata/featureflag/featureflag.go)0
-rw-r--r--internal/featureflag/featureflag_test.go (renamed from internal/metadata/featureflag/featureflag_test.go)0
-rw-r--r--internal/featureflag/ff_fix_routing_with_additional_repository.go (renamed from internal/metadata/featureflag/ff_fix_routing_with_additional_repository.go)2
-rw-r--r--internal/featureflag/ff_geometric_repacking.go (renamed from internal/metadata/featureflag/ff_geometric_repacking.go)0
-rw-r--r--internal/featureflag/ff_localrepo_read_object_cached.go (renamed from internal/metadata/featureflag/ff_localrepo_read_object_cached.go)0
-rw-r--r--internal/featureflag/ff_pack_objects_limiting_remote_ip.go (renamed from internal/metadata/featureflag/ff_pack_objects_limiting_remote_ip.go)0
-rw-r--r--internal/featureflag/ff_run_cmd_in_cgroup.go (renamed from internal/metadata/featureflag/ff_run_cmd_in_cgroup.go)0
-rw-r--r--internal/git/catfile/cache.go2
-rw-r--r--internal/git/catfile/object_info_reader_test.go10
-rw-r--r--internal/git/command_factory_cgroup_test.go2
-rw-r--r--internal/git/command_options.go2
-rw-r--r--internal/git/execution_environment.go2
-rw-r--r--internal/git/gitpipe/catfile_info.go4
-rw-r--r--internal/git/gitpipe/catfile_info_test.go7
-rw-r--r--internal/git/gitpipe/catfile_object_test.go4
-rw-r--r--internal/git/gitpipe/pipeline_test.go12
-rw-r--r--internal/git/gitpipe/testhelper_test.go10
-rw-r--r--internal/git/gittest/objects.go9
-rw-r--r--internal/git/hooks_options.go4
-rw-r--r--internal/git/hooks_options_test.go2
-rw-r--r--internal/git/hooks_payload.go2
-rw-r--r--internal/git/hooks_payload_test.go2
-rw-r--r--internal/git/housekeeping/clean_stale_data.go168
-rw-r--r--internal/git/housekeeping/clean_stale_data_test.go81
-rw-r--r--internal/git/housekeeping/manager.go4
-rw-r--r--internal/git/housekeeping/optimization_strategy.go155
-rw-r--r--internal/git/housekeeping/optimization_strategy_test.go70
-rw-r--r--internal/git/housekeeping/optimize_repository.go2
-rw-r--r--internal/git/housekeeping/optimize_repository_ext_test.go2
-rw-r--r--internal/git/housekeeping/optimize_repository_test.go72
-rw-r--r--internal/git/housekeeping/testhelper_test.go2
-rw-r--r--internal/git/localrepo/commit_test.go6
-rw-r--r--internal/git/localrepo/config_test.go2
-rw-r--r--internal/git/localrepo/objects.go2
-rw-r--r--internal/git/localrepo/objects_test.go2
-rw-r--r--internal/git/localrepo/tree.go85
-rw-r--r--internal/git/localrepo/tree_test.go205
-rw-r--r--internal/git/objectpool/create_test.go2
-rw-r--r--internal/git/objectpool/fetch.go3
-rw-r--r--internal/git/objectpool/fetch_test.go6
-rw-r--r--internal/git/objectpool/link_test.go2
-rw-r--r--internal/git/objectpool/testhelper_test.go12
-rw-r--r--internal/git/remoterepo/repository_test.go2
-rw-r--r--internal/git/stats/repository_info.go79
-rw-r--r--internal/git/stats/repository_info_test.go290
-rw-r--r--internal/git/updateref/update_with_hooks.go2
-rw-r--r--internal/git/updateref/update_with_hooks_test.go25
-rw-r--r--internal/git/version.go8
-rw-r--r--internal/git2go/executor.go2
-rw-r--r--internal/git2go/featureflags_test.go2
-rw-r--r--internal/gitaly/client/dial.go2
-rw-r--r--internal/gitaly/client/dial_test.go4
-rw-r--r--internal/gitaly/config/sentry/sentry.go2
-rw-r--r--internal/gitaly/hook/custom.go19
-rw-r--r--internal/gitaly/hook/postreceive_test.go4
-rw-r--r--internal/gitaly/hook/prereceive_test.go4
-rw-r--r--internal/gitaly/hook/sidechannel.go2
-rw-r--r--internal/gitaly/hook/sidechannel_test.go2
-rw-r--r--internal/gitaly/hook/transactions_test.go2
-rw-r--r--internal/gitaly/hook/update_test.go4
-rw-r--r--internal/gitaly/maintenance/optimize_test.go2
-rw-r--r--internal/gitaly/repoutil/create.go3
-rw-r--r--internal/gitaly/repoutil/lock.go4
-rw-r--r--internal/gitaly/repoutil/remove.go119
-rw-r--r--internal/gitaly/repoutil/remove_test.go92
-rw-r--r--internal/gitaly/server/auth_test.go10
-rw-r--r--internal/gitaly/server/server.go22
-rw-r--r--internal/gitaly/server/server_factory.go4
-rw-r--r--internal/gitaly/server/server_factory_test.go2
-rw-r--r--internal/gitaly/service/dependencies.go4
-rw-r--r--internal/gitaly/service/diff/testdata/file-with-multiple-chunks-after.txt2
-rw-r--r--internal/gitaly/service/diff/testdata/file-with-multiple-chunks-before.txt2
-rw-r--r--internal/gitaly/service/diff/testdata/file-with-multiple-chunks-diff.txt2
-rw-r--r--internal/gitaly/service/hook/pack_objects.go2
-rw-r--r--internal/gitaly/service/hook/pack_objects_test.go4
-rw-r--r--internal/gitaly/service/hook/post_receive_test.go2
-rw-r--r--internal/gitaly/service/hook/pre_receive_test.go2
-rw-r--r--internal/gitaly/service/hook/reference_transaction_test.go4
-rw-r--r--internal/gitaly/service/hook/server.go2
-rw-r--r--internal/gitaly/service/hook/update_test.go2
-rw-r--r--internal/gitaly/service/internalgitaly/backup_repos.go87
-rw-r--r--internal/gitaly/service/internalgitaly/backup_repos_test.go161
-rw-r--r--internal/gitaly/service/internalgitaly/server.go22
-rw-r--r--internal/gitaly/service/internalgitaly/walkrepos_test.go11
-rw-r--r--internal/gitaly/service/objectpool/alternates.go42
-rw-r--r--internal/gitaly/service/objectpool/alternates_test.go33
-rw-r--r--internal/gitaly/service/objectpool/fetch_into_object_pool_test.go4
-rw-r--r--internal/gitaly/service/operations/apply_patch_test.go4
-rw-r--r--internal/gitaly/service/operations/branches_test.go16
-rw-r--r--internal/gitaly/service/operations/merge_test.go2
-rw-r--r--internal/gitaly/service/operations/rebase_test.go2
-rw-r--r--internal/gitaly/service/operations/squash_test.go2
-rw-r--r--internal/gitaly/service/operations/submodules.go6
-rw-r--r--internal/gitaly/service/operations/tags.go23
-rw-r--r--internal/gitaly/service/operations/tags_test.go161
-rw-r--r--internal/gitaly/service/operations/testhelper_test.go14
-rw-r--r--internal/gitaly/service/ref/delete_refs_test.go2
-rw-r--r--internal/gitaly/service/repository/apply_gitattributes_test.go4
-rw-r--r--internal/gitaly/service/repository/create_repository_from_bundle_test.go2
-rw-r--r--internal/gitaly/service/repository/create_repository_test.go2
-rw-r--r--internal/gitaly/service/repository/fetch_bundle_test.go2
-rw-r--r--internal/gitaly/service/repository/fetch_remote_test.go2
-rw-r--r--internal/gitaly/service/repository/license_test.go2
-rw-r--r--internal/gitaly/service/repository/optimize_test.go2
-rw-r--r--internal/gitaly/service/repository/prune_unreachable_objects.go2
-rw-r--r--internal/gitaly/service/repository/remove.go94
-rw-r--r--internal/gitaly/service/repository/replicate.go2
-rw-r--r--internal/gitaly/service/repository/replicate_test.go4
-rw-r--r--internal/gitaly/service/repository/set_custom_hooks_test.go2
-rw-r--r--internal/gitaly/service/repository/write_ref_test.go2
-rw-r--r--internal/gitaly/service/setup/register.go7
-rw-r--r--internal/gitaly/service/smarthttp/inforefs_test.go2
-rw-r--r--internal/gitaly/service/smarthttp/receive_pack_test.go6
-rw-r--r--internal/gitaly/service/smarthttp/testhelper_test.go2
-rw-r--r--internal/gitaly/service/smarthttp/upload_pack.go2
-rw-r--r--internal/gitaly/service/smarthttp/upload_pack_test.go2
-rw-r--r--internal/gitaly/service/ssh/receive_pack_test.go4
-rw-r--r--internal/gitaly/service/ssh/upload_pack.go2
-rw-r--r--internal/gitaly/service/ssh/upload_pack_test.go4
-rw-r--r--internal/gitaly/transaction/manager.go2
-rw-r--r--internal/gitaly/transaction/manager_test.go2
-rw-r--r--internal/gitaly/transaction/voting_test.go2
-rw-r--r--internal/grpc/backchannel/backchannel.go (renamed from internal/backchannel/backchannel.go)0
-rw-r--r--internal/grpc/backchannel/backchannel_example_test.go (renamed from internal/backchannel/backchannel_example_test.go)4
-rw-r--r--internal/grpc/backchannel/backchannel_test.go (renamed from internal/backchannel/backchannel_test.go)2
-rw-r--r--internal/grpc/backchannel/client.go (renamed from internal/backchannel/client.go)0
-rw-r--r--internal/grpc/backchannel/registry.go (renamed from internal/backchannel/registry.go)0
-rw-r--r--internal/grpc/backchannel/server.go (renamed from internal/backchannel/server.go)0
-rw-r--r--internal/grpc/dnsresolver/builder.go (renamed from internal/dnsresolver/builder.go)0
-rw-r--r--internal/grpc/dnsresolver/builder_test.go (renamed from internal/dnsresolver/builder_test.go)0
-rw-r--r--internal/grpc/dnsresolver/noop.go (renamed from internal/dnsresolver/noop.go)0
-rw-r--r--internal/grpc/dnsresolver/resolver.go (renamed from internal/dnsresolver/resolver.go)0
-rw-r--r--internal/grpc/dnsresolver/resolver_test.go (renamed from internal/dnsresolver/resolver_test.go)0
-rw-r--r--internal/grpc/dnsresolver/target.go (renamed from internal/dnsresolver/target.go)0
-rw-r--r--internal/grpc/dnsresolver/target_test.go (renamed from internal/dnsresolver/target_test.go)0
-rw-r--r--internal/grpc/dnsresolver/testhelper_test.go (renamed from internal/dnsresolver/testhelper_test.go)0
-rw-r--r--internal/grpc/grpcstats/stats.go (renamed from internal/grpcstats/stats.go)0
-rw-r--r--internal/grpc/grpcstats/stats_test.go (renamed from internal/grpcstats/stats_test.go)0
-rw-r--r--internal/grpc/grpcstats/testhelper_test.go (renamed from internal/grpcstats/testhelper_test.go)0
-rw-r--r--internal/grpc/listenmux/mux.go (renamed from internal/listenmux/mux.go)0
-rw-r--r--internal/grpc/listenmux/mux_test.go (renamed from internal/listenmux/mux_test.go)0
-rw-r--r--internal/grpc/metadata/metadata.go (renamed from internal/metadata/metadata.go)0
-rw-r--r--internal/grpc/metadata/metadata_test.go (renamed from internal/metadata/metadata_test.go)0
-rw-r--r--internal/grpc/middleware/cache/cache.go (renamed from internal/middleware/cache/cache.go)0
-rw-r--r--internal/grpc/middleware/cache/cache_test.go (renamed from internal/middleware/cache/cache_test.go)0
-rw-r--r--internal/grpc/middleware/cache/export_test.go (renamed from internal/middleware/cache/export_test.go)0
-rw-r--r--internal/grpc/middleware/cache/prometheus.go (renamed from internal/middleware/cache/prometheus.go)0
-rw-r--r--internal/grpc/middleware/commandstatshandler/commandstatshandler.go (renamed from internal/middleware/commandstatshandler/commandstatshandler.go)0
-rw-r--r--internal/grpc/middleware/commandstatshandler/commandstatshandler_test.go (renamed from internal/middleware/commandstatshandler/commandstatshandler_test.go)2
-rw-r--r--internal/grpc/middleware/featureflag/featureflag_handler.go (renamed from internal/middleware/featureflag/featureflag_handler.go)2
-rw-r--r--internal/grpc/middleware/featureflag/featureflag_handler_test.go (renamed from internal/middleware/featureflag/featureflag_handler_test.go)2
-rw-r--r--internal/grpc/middleware/limithandler/concurrency_limiter.go (renamed from internal/middleware/limithandler/concurrency_limiter.go)12
-rw-r--r--internal/grpc/middleware/limithandler/concurrency_limiter_test.go (renamed from internal/middleware/limithandler/concurrency_limiter_test.go)2
-rw-r--r--internal/grpc/middleware/limithandler/middleware.go (renamed from internal/middleware/limithandler/middleware.go)0
-rw-r--r--internal/grpc/middleware/limithandler/middleware_test.go (renamed from internal/middleware/limithandler/middleware_test.go)2
-rw-r--r--internal/grpc/middleware/limithandler/monitor.go (renamed from internal/middleware/limithandler/monitor.go)15
-rw-r--r--internal/grpc/middleware/limithandler/monitor_test.go422
-rw-r--r--internal/grpc/middleware/limithandler/rate_limiter.go (renamed from internal/middleware/limithandler/rate_limiter.go)0
-rw-r--r--internal/grpc/middleware/limithandler/rate_limiter_test.go (renamed from internal/middleware/limithandler/rate_limiter_test.go)0
-rw-r--r--internal/grpc/middleware/limithandler/stats.go (renamed from internal/middleware/limithandler/stats.go)0
-rw-r--r--internal/grpc/middleware/limithandler/stats_interceptor_test.go (renamed from internal/middleware/limithandler/stats_interceptor_test.go)4
-rw-r--r--internal/grpc/middleware/limithandler/stats_test.go (renamed from internal/middleware/limithandler/stats_test.go)0
-rw-r--r--internal/grpc/middleware/limithandler/testhelper_test.go (renamed from internal/middleware/limithandler/testhelper_test.go)0
-rw-r--r--internal/grpc/middleware/metadatahandler/metadatahandler.go (renamed from internal/middleware/metadatahandler/metadatahandler.go)0
-rw-r--r--internal/grpc/middleware/metadatahandler/metadatahandler_test.go (renamed from internal/middleware/metadatahandler/metadatahandler_test.go)0
-rw-r--r--internal/grpc/middleware/panichandler/LICENSE (renamed from internal/middleware/panichandler/LICENSE)0
-rw-r--r--internal/grpc/middleware/panichandler/README.md (renamed from internal/middleware/panichandler/README.md)0
-rw-r--r--internal/grpc/middleware/panichandler/panic_handler.go (renamed from internal/middleware/panichandler/panic_handler.go)0
-rw-r--r--internal/grpc/middleware/sentryhandler/sentryhandler.go (renamed from internal/middleware/sentryhandler/sentryhandler.go)0
-rw-r--r--internal/grpc/middleware/sentryhandler/sentryhandler_test.go (renamed from internal/middleware/sentryhandler/sentryhandler_test.go)0
-rw-r--r--internal/grpc/middleware/statushandler/statushandler.go (renamed from internal/middleware/statushandler/statushandler.go)0
-rw-r--r--internal/grpc/middleware/statushandler/statushandler_test.go (renamed from internal/middleware/statushandler/statushandler_test.go)0
-rw-r--r--internal/grpc/proxy/LICENSE.txt (renamed from internal/praefect/grpc-proxy/LICENSE.txt)0
-rw-r--r--internal/grpc/proxy/codec.go (renamed from internal/praefect/grpc-proxy/proxy/codec.go)0
-rw-r--r--internal/grpc/proxy/codec_test.go (renamed from internal/praefect/grpc-proxy/proxy/codec_test.go)0
-rw-r--r--internal/grpc/proxy/director.go (renamed from internal/praefect/grpc-proxy/proxy/director.go)0
-rw-r--r--internal/grpc/proxy/doc.go (renamed from internal/praefect/grpc-proxy/proxy/doc.go)0
-rw-r--r--internal/grpc/proxy/handler.go (renamed from internal/praefect/grpc-proxy/proxy/handler.go)2
-rw-r--r--internal/grpc/proxy/handler_ext_test.go (renamed from internal/praefect/grpc-proxy/proxy/handler_ext_test.go)4
-rw-r--r--internal/grpc/proxy/handler_test.go (renamed from internal/praefect/grpc-proxy/proxy/handler_test.go)0
-rw-r--r--internal/grpc/proxy/peeker.go (renamed from internal/praefect/grpc-proxy/proxy/peeker.go)0
-rw-r--r--internal/grpc/proxy/peeker_test.go (renamed from internal/praefect/grpc-proxy/proxy/peeker_test.go)4
-rw-r--r--internal/grpc/proxy/testhelper_test.go (renamed from internal/praefect/grpc-proxy/proxy/testhelper_test.go)4
-rw-r--r--internal/grpc/sidechannel/conn.go (renamed from internal/sidechannel/conn.go)0
-rw-r--r--internal/grpc/sidechannel/conn_test.go (renamed from internal/sidechannel/conn_test.go)0
-rw-r--r--internal/grpc/sidechannel/proxy.go (renamed from internal/sidechannel/proxy.go)2
-rw-r--r--internal/grpc/sidechannel/proxy_test.go (renamed from internal/sidechannel/proxy_test.go)6
-rw-r--r--internal/grpc/sidechannel/registry.go (renamed from internal/sidechannel/registry.go)0
-rw-r--r--internal/grpc/sidechannel/registry_test.go (renamed from internal/sidechannel/registry_test.go)0
-rw-r--r--internal/grpc/sidechannel/sidechannel.go (renamed from internal/sidechannel/sidechannel.go)4
-rw-r--r--internal/grpc/sidechannel/sidechannel_test.go (renamed from internal/sidechannel/sidechannel_test.go)4
-rw-r--r--internal/log/log_test.go2
-rw-r--r--internal/metadata/featureflag/ff_revlist_for_connectivity.go10
-rw-r--r--internal/middleware/limithandler/monitor_test.go169
-rw-r--r--internal/praefect/coordinator.go8
-rw-r--r--internal/praefect/coordinator_test.go8
-rw-r--r--internal/praefect/grpc-proxy/README.md59
-rwxr-xr-xinternal/praefect/grpc-proxy/checkup.sh21
-rwxr-xr-xinternal/praefect/grpc-proxy/fixup.sh31
-rw-r--r--internal/praefect/grpc-proxy/proxy/DOC.md83
l---------internal/praefect/grpc-proxy/proxy/README.md1
-rw-r--r--internal/praefect/grpc-proxy/proxy/examples_test.go63
-rw-r--r--internal/praefect/info_service_test.go4
-rw-r--r--internal/praefect/middleware/errorhandler_test.go2
-rw-r--r--internal/praefect/node.go2
-rw-r--r--internal/praefect/nodes/manager.go4
-rw-r--r--internal/praefect/nodes/sql_elector_test.go4
-rw-r--r--internal/praefect/reconciler/reconciler_test.go2
-rw-r--r--internal/praefect/remove_all_test.go2
-rw-r--r--internal/praefect/remove_repository_test.go2
-rw-r--r--internal/praefect/replicator.go2
-rw-r--r--internal/praefect/replicator_test.go2
-rw-r--r--internal/praefect/repocleaner/repository_test.go2
-rw-r--r--internal/praefect/repository_exists_test.go2
-rw-r--r--internal/praefect/router_per_repository.go2
-rw-r--r--internal/praefect/router_per_repository_test.go2
-rw-r--r--internal/praefect/server.go16
-rw-r--r--internal/praefect/server_factory.go2
-rw-r--r--internal/praefect/server_factory_test.go6
-rw-r--r--internal/praefect/server_test.go6
-rw-r--r--internal/praefect/service/server/info.go2
-rw-r--r--internal/praefect/testserver.go2
-rw-r--r--internal/praefect/verifier_test.go4
-rw-r--r--internal/testhelper/featureset.go2
-rw-r--r--internal/testhelper/featureset_test.go2
-rw-r--r--internal/testhelper/leakage.go2
-rw-r--r--internal/testhelper/testhelper.go2
-rw-r--r--internal/testhelper/testserver/gitaly.go4
-rw-r--r--internal/transaction/txinfo/transaction.go2
-rw-r--r--proto/go/gitalypb/internal.pb.go289
-rw-r--r--proto/go/gitalypb/internal_grpc.pb.go74
-rw-r--r--proto/go/gitalypb/testproto/error_metadata.pb.go7
-rw-r--r--proto/go/gitalypb/testproto/invalid.pb.go7
-rw-r--r--proto/go/gitalypb/testproto/valid.pb.go7
-rw-r--r--proto/internal.proto35
-rw-r--r--proto/testproto/error_metadata.proto2
-rw-r--r--proto/testproto/invalid.proto2
-rw-r--r--proto/testproto/valid.proto2
274 files changed, 3352 insertions, 1632 deletions
diff --git a/.golangci.yml b/.golangci.yml
index 6d1e9c0f2..88ac72af8 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -56,7 +56,7 @@ linters-settings:
- (*database/sql.DB).Close
- (*database/sql.Rows).Close
- (*gitlab.com/gitlab-org/gitaly/v16/client.Pool).Close
- - (*gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel.ServerConn).Close
+ - (*gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel.ServerConn).Close
- (*gitlab.com/gitlab-org/gitaly/v16/internal/streamcache.pipe).Close
- (*gitlab.com/gitlab-org/gitaly/v16/internal/streamcache.pipeReader).Close
- (*google.golang.org/grpc.ClientConn).Close
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb7bb57a1..d94e3ec26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Gitaly changelog
+## 15.11.4 (2023-05-16)
+
+No changes.
+
## 15.11.3 (2023-05-10)
### Security (1 change)
diff --git a/client/dial.go b/client/dial.go
index 434b2c727..b29e9f372 100644
--- a/client/dial.go
+++ b/client/dial.go
@@ -7,9 +7,9 @@ import (
"github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/backoff"
- "gitlab.com/gitlab-org/gitaly/v16/internal/dnsresolver"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/dnsresolver"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"google.golang.org/grpc"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
)
diff --git a/client/sidechannel.go b/client/sidechannel.go
index 0741d07cc..4375d780a 100644
--- a/client/sidechannel.go
+++ b/client/sidechannel.go
@@ -5,9 +5,9 @@ import (
"io"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
diff --git a/cmd/gitaly-git2go/featureflags.go b/cmd/gitaly-git2go/featureflags.go
index fbe716209..055f18be9 100644
--- a/cmd/gitaly-git2go/featureflags.go
+++ b/cmd/gitaly-git2go/featureflags.go
@@ -7,8 +7,8 @@ import (
"encoding/gob"
"flag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git2go"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
)
// This subcommand is only called in tests, so we don't want to register it like
diff --git a/cmd/gitaly-git2go/main.go b/cmd/gitaly-git2go/main.go
index 27ee407f2..419dd4551 100644
--- a/cmd/gitaly-git2go/main.go
+++ b/cmd/gitaly-git2go/main.go
@@ -13,9 +13,9 @@ import (
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
git "github.com/libgit2/git2go/v34"
"github.com/sirupsen/logrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git2go"
glog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/labkit/correlation"
)
diff --git a/cmd/gitaly-hooks/hooks.go b/cmd/gitaly-hooks/hooks.go
index 4a87420dc..c6c422daa 100644
--- a/cmd/gitaly-hooks/hooks.go
+++ b/cmd/gitaly-hooks/hooks.go
@@ -13,11 +13,11 @@ import (
"github.com/sirupsen/logrus"
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
"gitlab.com/gitlab-org/gitaly/v16/client"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/env"
gitalylog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/stream"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/cmd/gitaly-hooks/hooks_test.go b/cmd/gitaly-hooks/hooks_test.go
index a4b7fac04..a74ce2eae 100644
--- a/cmd/gitaly-hooks/hooks_test.go
+++ b/cmd/gitaly-hooks/hooks_test.go
@@ -17,6 +17,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
@@ -26,11 +27,10 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
gitalylog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
@@ -787,7 +787,9 @@ remote: error executing git hook
t.Run(tc.name, func(t *testing.T) {
testhelper.SkipQuarantinedTest(t,
"https://gitlab.com/gitlab-org/gitaly/-/issues/5105",
- "TestGitalyServerReturnsError_packObjects/resource_exhausted_with_LimitError_detail")
+ "TestGitalyServerReturnsError_packObjects/resource_exhausted_with_LimitError_detail",
+ "TestGitalyServerReturnsError_packObjects/resource_exhausted_without_LimitError_detail",
+ )
logDir := testhelper.TempDir(t)
diff --git a/cmd/gitaly-ssh/main.go b/cmd/gitaly-ssh/main.go
index 813dfc576..96864f65a 100644
--- a/cmd/gitaly-ssh/main.go
+++ b/cmd/gitaly-ssh/main.go
@@ -11,8 +11,8 @@ import (
"github.com/sirupsen/logrus"
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
"gitlab.com/gitlab-org/gitaly/v16/client"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
internalclient "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/labkit/tracing"
"google.golang.org/grpc"
)
diff --git a/doc/PROCESS.md b/doc/PROCESS.md
index c4e09da5f..ba695920a 100644
--- a/doc/PROCESS.md
+++ b/doc/PROCESS.md
@@ -137,7 +137,7 @@ in detail in the following sections.
/chatops run feature set gitaly_go_find_license true --staging
```
-[gitaly-featureflag-folder]: https://gitlab.com/gitlab-org/gitaly/-/tree/master/internal/metadata/featureflag
+[gitaly-featureflag-folder]: https://gitlab.com/gitlab-org/gitaly/-/tree/master/internal/featureflag
[test-featureset]: https://gitlab.com/gitlab-org/gitaly/blob/c6fb49b9c6e854c0a2803f53106af501d6006cb8/internal/testhelper/featureset.go#L55-55
### Flag management with chatops
diff --git a/doc/protobuf.md b/doc/protobuf.md
index 94831731a..c086caa73 100644
--- a/doc/protobuf.md
+++ b/doc/protobuf.md
@@ -14,6 +14,11 @@ in their respective subdirectories. The list of RPCs can be
Run `make proto` from the root of the repository to regenerate the client
libraries after updating .proto files.
+## Gitaly RPC documentation
+
+For documentation generated from the protobuf definitions (in `proto/` directory),
+see [Gitaly RPC documentation](https://gitlab-org.gitlab.io/gitaly/).
+
See
[`developers.google.com`](https://developers.google.com/protocol-buffers/docs/proto3)
for documentation of the 'proto3' Protocol buffer specification
diff --git a/go.mod b/go.mod
index d3b388754..e9988f91d 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ replace github.com/go-enry/go-license-detector/v4 => github.com/gl-gitaly/go-lic
require (
github.com/ProtonMail/go-crypto v0.0.0-20230426101702-58e86b294756
- github.com/beevik/ntp v0.3.0
+ github.com/beevik/ntp v0.3.2
github.com/cloudflare/tableflip v1.2.3
github.com/containerd/cgroups v1.1.0
github.com/dgraph-io/badger/v3 v3.2103.5
@@ -27,9 +27,9 @@ require (
github.com/jackc/pgx/v4 v4.18.1
github.com/kelseyhightower/envconfig v1.4.0
github.com/libgit2/git2go/v34 v34.0.0
- github.com/miekg/dns v1.1.53
+ github.com/miekg/dns v1.1.54
github.com/olekukonko/tablewriter v0.0.5
- github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
+ github.com/opencontainers/runtime-spec v1.1.0-rc.2.0.20230511085824-0983f1d9e08f
github.com/opentracing/opentracing-go v1.2.0
github.com/pelletier/go-toml/v2 v2.0.7
github.com/prometheus/client_golang v1.15.1
@@ -41,7 +41,7 @@ require (
gitlab.com/gitlab-org/labkit v1.18.0
go.uber.org/goleak v1.2.1
gocloud.dev v0.29.0
- golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
+ golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea
golang.org/x/sync v0.2.0
golang.org/x/sys v0.8.0
golang.org/x/time v0.3.0
@@ -188,9 +188,9 @@ require (
go.uber.org/atomic v1.10.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/mod v0.8.0 // indirect
- golang.org/x/net v0.8.0 // indirect
+ golang.org/x/net v0.9.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
- golang.org/x/text v0.8.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gonum.org/v1/gonum v0.8.2 // indirect
diff --git a/go.sum b/go.sum
index 5f8b673e6..5a682fa78 100644
--- a/go.sum
+++ b/go.sum
@@ -627,8 +627,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiO
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
-github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
-github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
+github.com/beevik/ntp v0.3.2 h1:tWwrPRUDbURCK/Voh3Daxl2c60mOiA1z+bOqm4j/aSY=
+github.com/beevik/ntp v0.3.2/go.mod h1:hg8DSzEy+KlFOOmR19XMea1MsLaA6vojqM04e2IhuUo=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -1633,8 +1633,8 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
-github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
+github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
+github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
@@ -1775,8 +1775,9 @@ github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.1.0-rc.2.0.20230511085824-0983f1d9e08f h1:Li3QKbkyXFhrVfvLG+zMVgJRs1lEQ0qQBu77MTrxKSQ=
+github.com/opencontainers/runtime-spec v1.1.0-rc.2.0.20230511085824-0983f1d9e08f/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
@@ -2284,8 +2285,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4=
+golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -2412,8 +2413,9 @@ golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmL
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2640,8 +2642,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2656,8 +2658,9 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/internal/backup/backup.go b/internal/backup/backup.go
index c40e675fe..60fa0cd65 100644
--- a/internal/backup/backup.go
+++ b/internal/backup/backup.go
@@ -470,10 +470,15 @@ func (mgr *Manager) restoreBundle(ctx context.Context, path string, server stora
return nil
}
-func (mgr *Manager) writeCustomHooks(ctx context.Context, repo Repository, path string) error {
+func (mgr *Manager) writeCustomHooks(ctx context.Context, repo Repository, path string) (returnErr error) {
w := NewLazyWriter(func() (io.WriteCloser, error) {
return mgr.sink.GetWriter(ctx, path)
})
+ defer func() {
+ if err := w.Close(); err != nil && returnErr == nil {
+ returnErr = fmt.Errorf("write custom hooks: %w", err)
+ }
+ }()
if err := repo.GetCustomHooks(ctx, w); err != nil {
return fmt.Errorf("write custom hooks: %w", err)
}
diff --git a/internal/backup/repository.go b/internal/backup/repository.go
index 98d134468..6c2523908 100644
--- a/internal/backup/repository.go
+++ b/internal/backup/repository.go
@@ -213,7 +213,7 @@ func (r *localRepository) ListRefs(ctx context.Context) ([]git.Reference, error)
// GetCustomHooks fetches the custom hooks archive.
func (r *localRepository) GetCustomHooks(ctx context.Context, out io.Writer) error {
if err := repoutil.GetCustomHooks(ctx, r.locator, out, r.repo); err != nil {
- return fmt.Errorf("local repository: list refs: %w", err)
+ return fmt.Errorf("local repository: get custom hooks: %w", err)
}
return nil
}
diff --git a/internal/cache/diskcache_test.go b/internal/cache/diskcache_test.go
index ec19ddd9b..2db13ecde 100644
--- a/internal/cache/diskcache_test.go
+++ b/internal/cache/diskcache_test.go
@@ -9,9 +9,9 @@ import (
promtest "github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/cache/keyer.go b/internal/cache/keyer.go
index 609867750..db9620b23 100644
--- a/internal/cache/keyer.go
+++ b/internal/cache/keyer.go
@@ -15,9 +15,9 @@ import (
"github.com/google/uuid"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/version"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/cli/error.go b/internal/cli/error.go
new file mode 100644
index 000000000..1a33eb7a5
--- /dev/null
+++ b/internal/cli/error.go
@@ -0,0 +1,12 @@
+package cli
+
+import "fmt"
+
+// RequiredFlagError type is needed to produce the same error message as one from the
+// github.com/urfave/cli/v2 package. Unfortunately the errRequiredFlags type is not
+// exportable, and we can't utilise it.
+type RequiredFlagError string
+
+func (rf RequiredFlagError) Error() string {
+ return fmt.Sprintf("Required flag %q not set", string(rf))
+}
diff --git a/internal/cli/gitaly/serve.go b/internal/cli/gitaly/serve.go
index 120f3fdb0..e2c6c48ca 100644
--- a/internal/cli/gitaly/serve.go
+++ b/internal/cli/gitaly/serve.go
@@ -14,7 +14,6 @@ import (
"github.com/urfave/cli/v2"
"gitlab.com/gitlab-org/gitaly/v16"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/bootstrap"
"gitlab.com/gitlab-org/gitaly/v16/internal/bootstrap/starter"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
@@ -37,10 +36,11 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/env"
glog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/streamcache"
"gitlab.com/gitlab-org/gitaly/v16/internal/tempdir"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
diff --git a/internal/cli/praefect/main.go b/internal/cli/praefect/main.go
index e30332f74..23a6c7818 100644
--- a/internal/cli/praefect/main.go
+++ b/internal/cli/praefect/main.go
@@ -10,17 +10,6 @@
//
// praefect -config PATH_TO_CONFIG sql-ping
//
-// # SQL Migrate
-//
-// The subcommand "sql-migrate" will apply any outstanding SQL migrations.
-//
-// praefect -config PATH_TO_CONFIG sql-migrate [-ignore-unknown=true|false]
-//
-// By default, the migration will ignore any unknown migrations that are
-// not known by the Praefect binary.
-//
-// "-ignore-unknown=false" will disable this behavior.
-//
// The subcommand "sql-migrate-status" will show which SQL migrations have
// been applied and which ones have not:
//
@@ -78,6 +67,10 @@ func NewApp() *cli.App {
newDialNodesCommand(),
newListStoragesCommand(),
newListUntrackedRepositoriesCommand(),
+ newTrackRepositoryCommand(),
+ newVerifyCommand(),
+ newMetadataCommand(),
+ newSQLMigrateCommand(),
},
Flags: []cli.Flag{
&cli.StringFlag{
diff --git a/internal/cli/praefect/serve.go b/internal/cli/praefect/serve.go
index 22260e500..328459ef6 100644
--- a/internal/cli/praefect/serve.go
+++ b/internal/cli/praefect/serve.go
@@ -16,10 +16,11 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/bootstrap"
"gitlab.com/gitlab-org/gitaly/v16/internal/bootstrap/starter"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/sentry"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect"
@@ -35,7 +36,6 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/transactions"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/version"
"gitlab.com/gitlab-org/labkit/monitoring"
"gitlab.com/gitlab-org/labkit/tracing"
diff --git a/internal/cli/praefect/subcmd.go b/internal/cli/praefect/subcmd.go
index ef7e2282a..74ddeddf1 100644
--- a/internal/cli/praefect/subcmd.go
+++ b/internal/cli/praefect/subcmd.go
@@ -34,15 +34,11 @@ const (
func subcommands(logger *logrus.Entry) map[string]subcmd {
return map[string]subcmd{
sqlPingCmdName: &sqlPingSubcommand{},
- sqlMigrateCmdName: newSQLMigrateSubCommand(os.Stdout),
sqlMigrateDownCmdName: &sqlMigrateDownSubcommand{},
sqlMigrateStatusCmdName: &sqlMigrateStatusSubcommand{},
setReplicationFactorCmdName: newSetReplicatioFactorSubcommand(os.Stdout),
removeRepositoryCmdName: newRemoveRepository(logger, os.Stdout),
- trackRepositoryCmdName: newTrackRepository(logger, os.Stdout),
trackRepositoriesCmdName: newTrackRepositories(logger, os.Stdout),
- metadataCmdName: newMetadataSubcommand(os.Stdout),
- verifyCmdName: newVerifySubcommand(os.Stdout),
}
}
diff --git a/internal/cli/praefect/subcmd_metadata.go b/internal/cli/praefect/subcmd_metadata.go
index 1cce06899..30ef2d516 100644
--- a/internal/cli/praefect/subcmd_metadata.go
+++ b/internal/cli/praefect/subcmd_metadata.go
@@ -1,96 +1,109 @@
package praefect
import (
- "context"
"errors"
- "flag"
"fmt"
- "io"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
+ "github.com/urfave/cli/v2"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
-const metadataCmdName = "metadata"
-
-type metadataSubcommand struct {
- stdout io.Writer
- repositoryID int64
- virtualStorage string
- relativePath string
-}
-
-func newMetadataSubcommand(stdout io.Writer) *metadataSubcommand {
- return &metadataSubcommand{stdout: stdout}
-}
-
-func (cmd *metadataSubcommand) FlagSet() *flag.FlagSet {
- fs := flag.NewFlagSet(metadataCmdName, flag.ContinueOnError)
- fs.Int64Var(&cmd.repositoryID, "repository-id", 0, "the repository's ID")
- fs.StringVar(&cmd.virtualStorage, "virtual-storage", "", "the repository's virtual storage")
- fs.StringVar(&cmd.relativePath, "relative-path", "", "the repository's relative path in the virtual storage")
- return fs
-}
-
-func (cmd *metadataSubcommand) println(format string, args ...interface{}) {
- fmt.Fprintf(cmd.stdout, format+"\n", args...)
+func newMetadataCommand() *cli.Command {
+ return &cli.Command{
+ Name: "metadata",
+ Usage: "shows metadata information about repository",
+ Description: "The command provides metadata information about the repository. It includes " +
+ "identifier of the repository, path on the disk for it and it's replicas, information " +
+ "about replicas such as if it is assigned or not, its generation, health state, the storage, " +
+ "if it is a valid primary, etc. It can be invoked by providing repository identifier or " +
+ "virtual repository name and relative path.",
+ HideHelpCommand: true,
+ Action: metadataAction,
+ Flags: []cli.Flag{
+ &cli.Int64Flag{
+ Name: "repository-id",
+ Usage: "the repository's ID",
+ },
+ &cli.StringFlag{
+ Name: paramVirtualStorage,
+ Usage: "the repository's virtual storage",
+ },
+ &cli.StringFlag{
+ Name: "relative-path",
+ Usage: "the repository's relative path in the virtual storage",
+ },
+ },
+ Before: func(ctx *cli.Context) error {
+ if ctx.Args().Present() {
+ _ = cli.ShowSubcommandHelp(ctx)
+ return cli.Exit(unexpectedPositionalArgsError{Command: ctx.Command.Name}, 1)
+ }
+ return nil
+ },
+ }
}
-func (cmd *metadataSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) error {
- if flags.NArg() > 0 {
- return unexpectedPositionalArgsError{Command: flags.Name()}
+func metadataAction(appCtx *cli.Context) error {
+ logger := log.Default()
+ conf, err := getConfig(logger, appCtx.String(configFlagName))
+ if err != nil {
+ return err
}
+ repositoryID := appCtx.Int64("repository-id")
+ virtualStorage := appCtx.String(paramVirtualStorage)
+ relativePath := appCtx.String("relative-path")
+
var request gitalypb.GetRepositoryMetadataRequest
switch {
- case cmd.repositoryID != 0:
- if cmd.virtualStorage != "" || cmd.relativePath != "" {
+ case repositoryID != 0:
+ if virtualStorage != "" || relativePath != "" {
return errors.New("virtual storage and relative path can't be provided with a repository ID")
}
- request.Query = &gitalypb.GetRepositoryMetadataRequest_RepositoryId{RepositoryId: cmd.repositoryID}
- case cmd.virtualStorage != "" || cmd.relativePath != "":
- if cmd.virtualStorage == "" {
+ request.Query = &gitalypb.GetRepositoryMetadataRequest_RepositoryId{RepositoryId: repositoryID}
+ case virtualStorage != "" || relativePath != "":
+ if virtualStorage == "" {
return errors.New("virtual storage is required with relative path")
- } else if cmd.relativePath == "" {
+ } else if relativePath == "" {
return errors.New("relative path is required with virtual storage")
}
request.Query = &gitalypb.GetRepositoryMetadataRequest_Path_{
Path: &gitalypb.GetRepositoryMetadataRequest_Path{
- VirtualStorage: cmd.virtualStorage,
- RelativePath: cmd.relativePath,
+ VirtualStorage: virtualStorage,
+ RelativePath: relativePath,
},
}
default:
return errors.New("repository id or virtual storage and relative path required")
}
- nodeAddr, err := getNodeAddress(cfg)
+ nodeAddr, err := getNodeAddress(conf)
if err != nil {
return fmt.Errorf("get node address: %w", err)
}
- ctx := context.TODO()
- conn, err := subCmdDial(ctx, nodeAddr, cfg.Auth.Token, defaultDialTimeout)
+ conn, err := subCmdDial(appCtx.Context, nodeAddr, conf.Auth.Token, defaultDialTimeout)
if err != nil {
return fmt.Errorf("dial: %w", err)
}
defer conn.Close()
- metadata, err := gitalypb.NewPraefectInfoServiceClient(conn).GetRepositoryMetadata(ctx, &request)
+ metadata, err := gitalypb.NewPraefectInfoServiceClient(conn).GetRepositoryMetadata(appCtx.Context, &request)
if err != nil {
return fmt.Errorf("get metadata: %w", err)
}
- cmd.println("Repository ID: %d", metadata.RepositoryId)
- cmd.println("Virtual Storage: %q", metadata.VirtualStorage)
- cmd.println("Relative Path: %q", metadata.RelativePath)
- cmd.println("Replica Path: %q", metadata.ReplicaPath)
- cmd.println("Primary: %q", metadata.Primary)
- cmd.println("Generation: %d", metadata.Generation)
- cmd.println("Replicas:")
+ fmt.Fprintf(appCtx.App.Writer, "Repository ID: %d\n", metadata.RepositoryId)
+ fmt.Fprintf(appCtx.App.Writer, "Virtual Storage: %q\n", metadata.VirtualStorage)
+ fmt.Fprintf(appCtx.App.Writer, "Relative Path: %q\n", metadata.RelativePath)
+ fmt.Fprintf(appCtx.App.Writer, "Replica Path: %q\n", metadata.ReplicaPath)
+ fmt.Fprintf(appCtx.App.Writer, "Primary: %q\n", metadata.Primary)
+ fmt.Fprintf(appCtx.App.Writer, "Generation: %d\n", metadata.Generation)
+ fmt.Fprintf(appCtx.App.Writer, "Replicas:\n")
for _, replica := range metadata.Replicas {
- cmd.println("- Storage: %q", replica.Storage)
- cmd.println(" Assigned: %v", replica.Assigned)
+ fmt.Fprintf(appCtx.App.Writer, "- Storage: %q\n", replica.Storage)
+ fmt.Fprintf(appCtx.App.Writer, " Assigned: %v\n", replica.Assigned)
generationText := fmt.Sprintf("%d, fully up to date", replica.Generation)
if replica.Generation == -1 {
@@ -104,10 +117,10 @@ func (cmd *metadataSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro
verifiedAt = replica.VerifiedAt.AsTime().String()
}
- cmd.println(" Generation: %s", generationText)
- cmd.println(" Healthy: %v", replica.Healthy)
- cmd.println(" Valid Primary: %v", replica.ValidPrimary)
- cmd.println(" Verified At: %s", verifiedAt)
+ fmt.Fprintf(appCtx.App.Writer, " Generation: %s\n", generationText)
+ fmt.Fprintf(appCtx.App.Writer, " Healthy: %v\n", replica.Healthy)
+ fmt.Fprintf(appCtx.App.Writer, " Valid Primary: %v\n", replica.ValidPrimary)
+ fmt.Fprintf(appCtx.App.Writer, " Verified At: %s\n", verifiedAt)
}
return nil
}
diff --git a/internal/cli/praefect/subcmd_metadata_test.go b/internal/cli/praefect/subcmd_metadata_test.go
index bfce0350d..05db30b7e 100644
--- a/internal/cli/praefect/subcmd_metadata_test.go
+++ b/internal/cli/praefect/subcmd_metadata_test.go
@@ -4,10 +4,12 @@ import (
"bytes"
"errors"
"fmt"
+ "io"
"testing"
"time"
"github.com/stretchr/testify/require"
+ "github.com/urfave/cli/v2"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/info"
@@ -22,7 +24,7 @@ func TestMetadataSubcommand(t *testing.T) {
ctx := testhelper.Context(t)
tx := testdb.New(t).Begin(t)
- defer tx.Rollback(t)
+ t.Cleanup(func() { tx.Rollback(t) })
testdb.SetHealthyNodes(t, ctx, tx, map[string]map[string][]string{
"praefect": {"virtual-storage": {"primary", "secondary-1"}},
@@ -42,7 +44,23 @@ func TestMetadataSubcommand(t *testing.T) {
ln, clean := listenAndServe(t, []svcRegistrar{
registerPraefectInfoServer(info.NewServer(config.Config{}, rs, nil, nil, nil)),
})
- defer clean()
+ t.Cleanup(clean)
+
+ conf := config.Config{
+ SocketPath: ln.Addr().String(),
+ VirtualStorages: []*config.VirtualStorage{
+ {
+ Name: "vs-1",
+ Nodes: []*config.Node{
+ {
+ Storage: "storage-1",
+ Address: "tcp://1.2.3.4",
+ },
+ },
+ },
+ },
+ }
+ confPath := writeConfigToFile(t, conf)
for _, tc := range []struct {
desc string
@@ -50,6 +68,11 @@ func TestMetadataSubcommand(t *testing.T) {
error error
}{
{
+ desc: "positional arguments",
+ args: []string{"positional-arg"},
+ error: cli.Exit(unexpectedPositionalArgsError{Command: "metadata"}, 1),
+ },
+ {
desc: "missing parameters fails",
error: errors.New("repository id or virtual storage and relative path required"),
},
@@ -87,14 +110,28 @@ func TestMetadataSubcommand(t *testing.T) {
args: []string{"-virtual-storage=virtual-storage", "-relative-path=relative-path"},
},
} {
+ tc := tc
t.Run(tc.desc, func(t *testing.T) {
- stdout := &bytes.Buffer{}
- cmd := newMetadataSubcommand(stdout)
+ t.Parallel()
- fs := cmd.FlagSet()
- require.NoError(t, fs.Parse(tc.args))
- err := cmd.Exec(fs, config.Config{SocketPath: ln.Addr().String()})
- testhelper.RequireGrpcError(t, tc.error, err)
+ var stdout bytes.Buffer
+ app := cli.App{
+ Reader: bytes.NewReader(nil),
+ Writer: &stdout,
+ ErrWriter: io.Discard,
+ HideHelpCommand: true,
+ Commands: []*cli.Command{
+ newMetadataCommand(),
+ },
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "config",
+ Value: confPath,
+ },
+ },
+ }
+ err := app.Run(append([]string{progname, "metadata"}, tc.args...))
+ require.Equal(t, tc.error, err)
if tc.error != nil {
return
}
diff --git a/internal/cli/praefect/subcmd_sql_migrate.go b/internal/cli/praefect/subcmd_sql_migrate.go
index 57020bb7b..46d941113 100644
--- a/internal/cli/praefect/subcmd_sql_migrate.go
+++ b/internal/cli/praefect/subcmd_sql_migrate.go
@@ -1,13 +1,12 @@
package praefect
import (
- "flag"
"fmt"
- "io"
"time"
migrate "github.com/rubenv/sql-migrate"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
+ "github.com/urfave/cli/v2"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore/glsql"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore/migrations"
)
@@ -17,25 +16,42 @@ const (
timeFmt = "2006-01-02T15:04:05"
)
-type sqlMigrateSubcommand struct {
- w io.Writer
- ignoreUnknown bool
- verbose bool
-}
-
-func newSQLMigrateSubCommand(writer io.Writer) *sqlMigrateSubcommand {
- return &sqlMigrateSubcommand{w: writer}
-}
-
-func (cmd *sqlMigrateSubcommand) FlagSet() *flag.FlagSet {
- flags := flag.NewFlagSet(sqlMigrateCmdName, flag.ExitOnError)
- flags.BoolVar(&cmd.ignoreUnknown, "ignore-unknown", true, "ignore unknown migrations (default is true)")
- flags.BoolVar(&cmd.verbose, "verbose", false, "show text of migration query (default is false)")
- return flags
+func newSQLMigrateCommand() *cli.Command {
+ return &cli.Command{
+ Name: sqlMigrateCmdName,
+ Usage: "apply outstanding SQL migrations",
+ Description: "The sql-migrate subcommand applies outstanding migrations to the configured database.\n" +
+ "The subcommand doesn't fail if database has migrations unknown to the version of Praefect you're using.\n" +
+ "To make the subcommand fail on unknown migrations, use the 'ignore-unknown' flag.",
+ HideHelpCommand: true,
+ Action: sqlMigrateAction,
+ Flags: []cli.Flag{
+ &cli.BoolFlag{
+ Name: "ignore-unknown",
+ Usage: "ignore unknown migrations",
+ Value: true,
+ },
+ &cli.BoolFlag{
+ Name: "verbose",
+ Usage: "show text of migration query",
+ },
+ },
+ Before: func(ctx *cli.Context) error {
+ if ctx.Args().Present() {
+ _ = cli.ShowSubcommandHelp(ctx)
+ return cli.Exit(unexpectedPositionalArgsError{Command: ctx.Command.Name}, 1)
+ }
+ return nil
+ },
+ }
}
-func (cmd *sqlMigrateSubcommand) Exec(flags *flag.FlagSet, conf config.Config) error {
- const subCmd = progname + " " + sqlMigrateCmdName
+func sqlMigrateAction(appCtx *cli.Context) error {
+ logger := log.Default()
+ conf, err := getConfig(logger, appCtx.String(configFlagName))
+ if err != nil {
+ return err
+ }
db, clean, err := openDB(conf.DB)
if err != nil {
@@ -43,8 +59,9 @@ func (cmd *sqlMigrateSubcommand) Exec(flags *flag.FlagSet, conf config.Config) e
}
defer clean()
+ ignoreUnknown := appCtx.Bool("ignore-unknown")
migrationSet := migrate.MigrationSet{
- IgnoreUnknown: cmd.ignoreUnknown,
+ IgnoreUnknown: ignoreUnknown,
TableName: migrations.MigrationTableName,
}
@@ -55,40 +72,41 @@ func (cmd *sqlMigrateSubcommand) Exec(flags *flag.FlagSet, conf config.Config) e
// Find all migrations that are currently down.
planMigrations, _, _ := migrationSet.PlanMigration(db, "postgres", planSource, migrate.Up, 0)
+ subCmd := progname + " " + appCtx.Command.Name
if len(planMigrations) == 0 {
- fmt.Fprintf(cmd.w, "%s: all migrations are up\n", subCmd)
+ fmt.Fprintf(appCtx.App.Writer, "%s: all migrations are up\n", subCmd)
return nil
}
- fmt.Fprintf(cmd.w, "%s: migrations to apply: %d\n\n", subCmd, len(planMigrations))
+ fmt.Fprintf(appCtx.App.Writer, "%s: migrations to apply: %d\n\n", subCmd, len(planMigrations))
executed := 0
for _, mig := range planMigrations {
- fmt.Fprintf(cmd.w, "= %s %v: migrating\n", time.Now().Format(timeFmt), mig.Id)
+ fmt.Fprintf(appCtx.App.Writer, "= %s %v: migrating\n", time.Now().Format(timeFmt), mig.Id)
start := time.Now()
- if cmd.verbose {
- fmt.Fprintf(cmd.w, "\t%v\n", mig.Up)
+ if appCtx.Bool("verbose") {
+ fmt.Fprintf(appCtx.App.Writer, "\t%v\n", mig.Up)
}
- n, err := glsql.MigrateSome(mig.Migration, db, cmd.ignoreUnknown)
+ n, err := glsql.MigrateSome(mig.Migration, db, ignoreUnknown)
if err != nil {
return fmt.Errorf("%s: fail: %w", time.Now().Format(timeFmt), err)
}
if n > 0 {
- fmt.Fprintf(cmd.w, "== %s %v: applied (%s)\n", time.Now().Format(timeFmt), mig.Id, time.Since(start))
+ fmt.Fprintf(appCtx.App.Writer, "== %s %v: applied (%s)\n", time.Now().Format(timeFmt), mig.Id, time.Since(start))
// Additional migrations were run. No harm, but prevents us from tracking their execution duration.
if n > 1 {
- fmt.Fprintf(cmd.w, "warning: %v additional migrations were applied successfully\n", n-1)
+ fmt.Fprintf(appCtx.App.Writer, "warning: %v additional migrations were applied successfully\n", n-1)
}
} else {
- fmt.Fprintf(cmd.w, "== %s %v: skipped (%s)\n", time.Now().Format(timeFmt), mig.Id, time.Since(start))
+ fmt.Fprintf(appCtx.App.Writer, "== %s %v: skipped (%s)\n", time.Now().Format(timeFmt), mig.Id, time.Since(start))
}
executed += n
}
- fmt.Fprintf(cmd.w, "\n%s: OK (applied %d migrations)\n", subCmd, executed)
+ fmt.Fprintf(appCtx.App.Writer, "\n%s: OK (applied %d migrations)\n", subCmd, executed)
return nil
}
diff --git a/internal/cli/praefect/subcmd_sql_migrate_test.go b/internal/cli/praefect/subcmd_sql_migrate_test.go
index 535c091fa..9fae09ca8 100644
--- a/internal/cli/praefect/subcmd_sql_migrate_test.go
+++ b/internal/cli/praefect/subcmd_sql_migrate_test.go
@@ -2,11 +2,12 @@ package praefect
import (
"bytes"
- "flag"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/urfave/cli/v2"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore/migrations"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testdb"
@@ -15,17 +16,28 @@ import (
func TestSubCmdSqlMigrate(t *testing.T) {
db := testdb.New(t)
dbCfg := testdb.GetConfig(t, db.Name)
- cfg := config.Config{DB: dbCfg}
+ cfg := config.Config{
+ ListenAddr: "/dev/null",
+ VirtualStorages: []*config.VirtualStorage{{Name: "p", Nodes: []*config.Node{{Storage: "s", Address: "localhost"}}}},
+ DB: dbCfg,
+ }
+ confPath := writeConfigToFile(t, cfg)
migrationCt := len(migrations.All())
for _, tc := range []struct {
desc string
up int
- verbose bool
+ args []string
expectedOutput []string
+ expectedErr error
}{
{
+ desc: "unexpected positional arguments",
+ args: []string{"positonal-arg"},
+ expectedErr: cli.Exit(unexpectedPositionalArgsError{Command: "sql-migrate"}, 1),
+ },
+ {
desc: "All migrations up",
up: migrationCt,
expectedOutput: []string{"praefect sql-migrate: all migrations are up"},
@@ -51,9 +63,9 @@ func TestSubCmdSqlMigrate(t *testing.T) {
},
},
{
- desc: "Verbose output",
- up: 0,
- verbose: true,
+ desc: "Verbose output",
+ up: 0,
+ args: []string{"-verbose"},
expectedOutput: []string{
fmt.Sprintf("praefect sql-migrate: migrations to apply: %d", migrationCt),
"20200109161404_hello_world: migrating",
@@ -67,9 +79,25 @@ func TestSubCmdSqlMigrate(t *testing.T) {
testdb.SetMigrations(t, db, cfg, tc.up)
var stdout bytes.Buffer
- migrateCmd := sqlMigrateSubcommand{w: &stdout, ignoreUnknown: true, verbose: tc.verbose}
- assert.NoError(t, migrateCmd.Exec(flag.NewFlagSet("", flag.PanicOnError), cfg))
-
+ var stderr bytes.Buffer
+ app := cli.App{
+ Reader: bytes.NewReader(nil),
+ Writer: &stdout,
+ ErrWriter: &stderr,
+ HideHelpCommand: true,
+ Commands: []*cli.Command{
+ newSQLMigrateCommand(),
+ },
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "config",
+ Value: confPath,
+ },
+ },
+ }
+ err := app.Run(append([]string{progname, sqlMigrateCmdName, "-ignore-unknown"}, tc.args...))
+ require.Equal(t, tc.expectedErr, err)
+ assert.Empty(t, stderr.String())
for _, out := range tc.expectedOutput {
assert.Contains(t, stdout.String(), out)
}
diff --git a/internal/cli/praefect/subcmd_track_repository.go b/internal/cli/praefect/subcmd_track_repository.go
index fd5ad5126..1c28cbe28 100644
--- a/internal/cli/praefect/subcmd_track_repository.go
+++ b/internal/cli/praefect/subcmd_track_repository.go
@@ -4,14 +4,16 @@ import (
"context"
"database/sql"
"errors"
- "flag"
"fmt"
"io"
"math/rand"
"time"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
+ "github.com/urfave/cli/v2"
+ glcli "gitlab.com/gitlab-org/gitaly/v16/internal/cli"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
@@ -27,13 +29,47 @@ const (
trackRepositoryCmdName = "track-repository"
)
-type trackRepository struct {
- w io.Writer
- logger logrus.FieldLogger
- virtualStorage string
- relativePath string
- authoritativeStorage string
- replicateImmediately bool
+func newTrackRepositoryCommand() *cli.Command {
+ return &cli.Command{
+ Name: trackRepositoryCmdName,
+ Usage: "Praefect starts to track given repository",
+ Description: "This command adds a given repository to be tracked by Praefect.\n" +
+ "It checks if the repository exists on disk on the authoritative storage,\n" +
+ "and whether database records are absent from tracking the repository.\n" +
+ "If the 'replicate-immediately' flag is used, the command will attempt to replicate\n" +
+ "the repository to the secondaries. The command is blocked until the\n" +
+ "replication finishes. Otherwise, replication jobs will be created and will " +
+ "be executed eventually by Praefect in the background.\n",
+ HideHelpCommand: true,
+ Action: trackRepositoryAction,
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: paramVirtualStorage,
+ Usage: "name of the repository's virtual storage",
+ Required: true,
+ },
+ &cli.StringFlag{
+ Name: paramRelativePath,
+ Usage: "relative path to the repository",
+ Required: true,
+ },
+ &cli.StringFlag{
+ Name: paramAuthoritativeStorage,
+ Usage: "storage with the repository to consider as authoritative",
+ },
+ &cli.BoolFlag{
+ Name: "replicate-immediately",
+ Usage: "kick off a replication immediately",
+ },
+ },
+ Before: func(ctx *cli.Context) error {
+ if ctx.Args().Present() {
+ _ = cli.ShowSubcommandHelp(ctx)
+ return cli.Exit(unexpectedPositionalArgsError{Command: ctx.Command.Name}, 1)
+ }
+ return nil
+ },
+ }
}
type trackRepositoryRequest struct {
@@ -44,39 +80,21 @@ type trackRepositoryRequest struct {
var errAuthoritativeRepositoryNotExist = errors.New("authoritative repository does not exist")
-func newTrackRepository(logger logrus.FieldLogger, w io.Writer) *trackRepository {
- return &trackRepository{w: w, logger: logger}
-}
-
-func (cmd *trackRepository) FlagSet() *flag.FlagSet {
- fs := flag.NewFlagSet(trackRepositoryCmdName, flag.ExitOnError)
- fs.StringVar(&cmd.virtualStorage, paramVirtualStorage, "", "name of the repository's virtual storage")
- fs.StringVar(&cmd.relativePath, paramRelativePath, "", "relative path to the repository")
- fs.StringVar(&cmd.authoritativeStorage, paramAuthoritativeStorage, "", "storage with the repository to consider as authoritative")
- fs.BoolVar(&cmd.replicateImmediately, "replicate-immediately", false, "kick off a replication immediately")
- fs.Usage = func() {
- printfErr("Description:\n" +
- " This command adds a given repository to be tracked by Praefect.\n" +
- " It checks if the repository exists on disk on the authoritative storage,\n" +
- " and whether database records are absent from tracking the repository.\n" +
- " If -replicate-immediately is used, the command will attempt to replicate the repository to the secondaries.\n" +
- " Otherwise, replication jobs will be created and will be executed eventually by Praefect itself.\n")
- fs.PrintDefaults()
+func trackRepositoryAction(appCtx *cli.Context) error {
+ logger := log.Default()
+ conf, err := getConfig(logger, appCtx.String(configFlagName))
+ if err != nil {
+ return err
}
- return fs
-}
-func (cmd trackRepository) Exec(flags *flag.FlagSet, cfg config.Config) error {
- switch {
- case flags.NArg() > 0:
- return unexpectedPositionalArgsError{Command: flags.Name()}
- case cmd.virtualStorage == "":
- return requiredParameterError(paramVirtualStorage)
- case cmd.relativePath == "":
- return requiredParameterError(paramRelativePath)
- case cmd.authoritativeStorage == "":
- if cfg.Failover.ElectionStrategy == config.ElectionStrategyPerRepository {
- return requiredParameterError(paramAuthoritativeStorage)
+ virtualStorage := appCtx.String(paramVirtualStorage)
+ relativePath := appCtx.String(paramRelativePath)
+ authoritativeStorage := appCtx.String(paramAuthoritativeStorage)
+ replicateImmediately := appCtx.Bool("replicate-immediately")
+
+ if authoritativeStorage == "" {
+ if conf.Failover.ElectionStrategy == config.ElectionStrategyPerRepository {
+ return glcli.RequiredFlagError(paramAuthoritativeStorage)
}
}
@@ -84,29 +102,24 @@ func (cmd trackRepository) Exec(flags *flag.FlagSet, cfg config.Config) error {
openDBCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
- db, err := glsql.OpenDB(openDBCtx, cfg.DB)
+ db, err := glsql.OpenDB(openDBCtx, conf.DB)
if err != nil {
return fmt.Errorf("connect to database: %w", err)
}
defer func() { _ = db.Close() }()
- return cmd.exec(ctx, db, cfg)
-}
-
-const trackRepoErrorPrefix = "attempting to track repository in praefect database"
-
-func (cmd *trackRepository) exec(ctx context.Context, db *sql.DB, cfg config.Config) error {
- logger := cmd.logger.WithField("correlation_id", correlation.ExtractFromContext(ctx))
-
req := trackRepositoryRequest{
- RelativePath: cmd.relativePath,
- AuthoritativeStorage: cmd.authoritativeStorage,
- VirtualStorage: cmd.virtualStorage,
+ RelativePath: relativePath,
+ AuthoritativeStorage: authoritativeStorage,
+ VirtualStorage: virtualStorage,
}
- return req.execRequest(ctx, db, cfg, cmd.w, logger, cmd.replicateImmediately)
+ logger = logger.WithField("correlation_id", correlation.ExtractFromContext(ctx))
+ return req.execRequest(ctx, db, conf, appCtx.App.Writer, logger, replicateImmediately)
}
+const trackRepoErrorPrefix = "attempting to track repository in praefect database"
+
func (req *trackRepositoryRequest) execRequest(ctx context.Context,
db *sql.DB,
cfg config.Config,
diff --git a/internal/cli/praefect/subcmd_track_repository_test.go b/internal/cli/praefect/subcmd_track_repository_test.go
index 56f33fc17..d721e51d9 100644
--- a/internal/cli/praefect/subcmd_track_repository_test.go
+++ b/internal/cli/praefect/subcmd_track_repository_test.go
@@ -2,15 +2,14 @@ package praefect
import (
"bytes"
- "flag"
- "net"
+ "io"
"path/filepath"
- "strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "github.com/urfave/cli/v2"
"gitlab.com/gitlab-org/gitaly/v16/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
@@ -25,62 +24,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
-func TestAddRepository_FlagSet(t *testing.T) {
- t.Parallel()
- cmd := &trackRepository{}
- fs := cmd.FlagSet()
- require.NoError(t, fs.Parse([]string{"--virtual-storage", "vs", "--repository", "repo", "--authoritative-storage", "storage-0"}))
- require.Equal(t, "vs", cmd.virtualStorage)
- require.Equal(t, "repo", cmd.relativePath)
- require.Equal(t, "storage-0", cmd.authoritativeStorage)
-}
-
-func TestAddRepository_Exec_invalidArgs(t *testing.T) {
- t.Parallel()
- t.Run("not all flag values processed", func(t *testing.T) {
- cmd := trackRepository{}
- flagSet := flag.NewFlagSet("cmd", flag.PanicOnError)
- require.NoError(t, flagSet.Parse([]string{"stub"}))
- err := cmd.Exec(flagSet, config.Config{})
- require.EqualError(t, err, "cmd doesn't accept positional arguments")
- })
-
- t.Run("virtual-storage is not set", func(t *testing.T) {
- cmd := trackRepository{}
- err := cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), config.Config{})
- require.EqualError(t, err, `"virtual-storage" is a required parameter`)
- })
-
- t.Run("repository is not set", func(t *testing.T) {
- cmd := trackRepository{virtualStorage: "stub"}
- err := cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), config.Config{})
- require.EqualError(t, err, `"repository" is a required parameter`)
- })
-
- t.Run("authoritative-storage is not set", func(t *testing.T) {
- cmd := trackRepository{virtualStorage: "stub", relativePath: "path/to/repo"}
- err := cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), config.Config{Failover: config.Failover{ElectionStrategy: config.ElectionStrategyPerRepository}})
- require.EqualError(t, err, `"authoritative-storage" is a required parameter`)
- })
-
- t.Run("db connection error", func(t *testing.T) {
- listener, addr := testhelper.GetLocalhostListener(t)
- require.NoError(t, listener.Close())
-
- host, portStr, err := net.SplitHostPort(addr)
- require.NoError(t, err)
- port, err := strconv.ParseUint(portStr, 10, 16)
- require.NoError(t, err)
-
- cmd := trackRepository{virtualStorage: "stub", relativePath: "stub", authoritativeStorage: "storage-0", logger: testhelper.NewDiscardingLogger(t)}
- cfg := config.Config{DB: config.DB{Host: host, Port: int(port), SSLMode: "disable"}}
- err = cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), cfg)
- require.Error(t, err)
- require.Contains(t, err.Error(), "connect to database: send ping: failed to connect to")
- })
-}
-
-func TestAddRepository_Exec(t *testing.T) {
+func TestTrackRepositorySubcommand(t *testing.T) {
t.Parallel()
g1Cfg := testcfg.Build(t, testcfg.WithStorages("gitaly-1"))
g2Cfg := testcfg.Build(t, testcfg.WithStorages("gitaly-2"))
@@ -117,6 +61,7 @@ func TestAddRepository_Exec(t *testing.T) {
ElectionStrategy: config.ElectionStrategyPerRepository,
},
}
+ confPath := writeConfigToFile(t, conf)
gitalyCC, err := client.Dial(g1Addr, nil)
require.NoError(t, err)
@@ -138,26 +83,129 @@ func TestAddRepository_Exec(t *testing.T) {
}
authoritativeStorage := g1Cfg.Storages[0].Name
- logger := testhelper.NewDiscardingLogger(t)
+ repoDS := datastore.NewPostgresRepositoryStore(db, conf.StorageNames())
+
+ relativePathAlreadyExist := "path/to/test/repo_2"
+ require.NoError(t, createRepoThroughGitaly1(relativePathAlreadyExist))
+ require.DirExists(t, filepath.Join(g1Cfg.Storages[0].Path, relativePathAlreadyExist))
+ require.NoDirExists(t, filepath.Join(g2Cfg.Storages[0].Path, relativePathAlreadyExist))
+ idRelativePathAlreadyExist, err := repoDS.ReserveRepositoryID(ctx, virtualStorageName, relativePathAlreadyExist)
+ require.NoError(t, err)
+ require.NoError(t, repoDS.CreateRepository(
+ ctx,
+ idRelativePathAlreadyExist,
+ virtualStorageName,
+ relativePathAlreadyExist,
+ relativePathAlreadyExist,
+ g1Cfg.Storages[0].Name,
+ nil,
+ nil,
+ true,
+ true,
+ ))
+
+ runCmd := func(t *testing.T, args []string) (string, error) {
+ var stdout bytes.Buffer
+ app := cli.App{
+ Reader: bytes.NewReader(nil),
+ Writer: &stdout,
+ ErrWriter: io.Discard,
+ HideHelpCommand: true,
+ Commands: []*cli.Command{
+ newTrackRepositoryCommand(),
+ },
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "config",
+ Value: confPath,
+ },
+ },
+ }
+ err := app.Run(append([]string{progname, trackRepositoryCmdName}, args...))
+ return stdout.String(), err
+ }
+
+ t.Run("fails", func(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ args []string
+ errorMsg string
+ }{
+ {
+ name: "positional arguments",
+ args: []string{"-virtual-storage=v", "-repository=r", "-authoritative-storage=s", "positional-arg"},
+ errorMsg: "track-repository doesn't accept positional arguments",
+ },
+ {
+ name: "virtual-storage is not set",
+ args: []string{
+ "-repository", "path/to/test/repo_1",
+ "-authoritative-storage", authoritativeStorage,
+ },
+ errorMsg: `Required flag "virtual-storage" not set`,
+ },
+ {
+ name: "repository is not set",
+ args: []string{
+ "-virtual-storage", virtualStorageName,
+ "-authoritative-storage", authoritativeStorage,
+ },
+ errorMsg: `Required flag "repository" not set`,
+ },
+ {
+ name: "authoritative-storage is not set",
+ args: []string{
+ "-virtual-storage", virtualStorageName,
+ "-repository", "path/to/test/repo_1",
+ },
+ errorMsg: `Required flag "authoritative-storage" not set`,
+ },
+ {
+ name: "repository does not exist",
+ args: []string{
+ "-virtual-storage", virtualStorageName,
+ "-repository", "path/to/test/repo_1",
+ "-authoritative-storage", authoritativeStorage,
+ },
+ errorMsg: "attempting to track repository in praefect database: authoritative repository does not exist",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ _, err := runCmd(t, tc.args)
+ require.EqualError(t, err, tc.errorMsg)
+ })
+ }
+ })
t.Run("ok", func(t *testing.T) {
testCases := []struct {
relativePath string
desc string
replicateImmediately bool
- expectedOutput string
+ repositoryExists bool
+ expectedOutput []string
}{
{
- relativePath: "path/to/test/repo1",
desc: "force replication",
+ relativePath: "path/to/test/repo1",
replicateImmediately: true,
- expectedOutput: "Finished replicating repository to \"gitaly-2\".\n",
+ expectedOutput: []string{"Finished replicating repository to \"gitaly-2\".\n"},
},
{
- relativePath: "path/to/test/repo2",
desc: "do not force replication",
+ relativePath: "path/to/test/repo2",
replicateImmediately: false,
- expectedOutput: "Added replication job to replicate repository to \"gitaly-2\".\n",
+ expectedOutput: []string{"Added replication job to replicate repository to \"gitaly-2\".\n"},
+ },
+ {
+ desc: "records already exist",
+ relativePath: relativePathAlreadyExist,
+ repositoryExists: true,
+ expectedOutput: []string{
+ "repository is already tracked in praefect database",
+ "Finished adding new repository to be tracked in praefect database.",
+ "Added replication job to replicate repository to \"gitaly-2\".\n",
+ },
},
}
@@ -178,27 +226,28 @@ func TestAddRepository_Exec(t *testing.T) {
nodeMgr.Start(0, time.Hour)
defer nodeMgr.Stop()
- repoDS := datastore.NewPostgresRepositoryStore(db, conf.StorageNames())
exists, err := repoDS.RepositoryExists(ctx, virtualStorageName, tc.relativePath)
require.NoError(t, err)
- require.False(t, exists)
+ require.Equal(t, tc.repositoryExists, exists)
// create the repo on Gitaly without Praefect knowing
- require.NoError(t, createRepoThroughGitaly1(tc.relativePath))
- require.DirExists(t, filepath.Join(g1Cfg.Storages[0].Path, tc.relativePath))
- require.NoDirExists(t, filepath.Join(g2Cfg.Storages[0].Path, tc.relativePath))
- var stdout bytes.Buffer
+ if !tc.repositoryExists {
+ require.NoError(t, createRepoThroughGitaly1(tc.relativePath))
+ require.DirExists(t, filepath.Join(g1Cfg.Storages[0].Path, tc.relativePath))
+ require.NoDirExists(t, filepath.Join(g2Cfg.Storages[0].Path, tc.relativePath))
+ }
- addRepoCmd := &trackRepository{
- logger: logger,
- virtualStorage: virtualStorageName,
- relativePath: tc.relativePath,
- authoritativeStorage: authoritativeStorage,
- replicateImmediately: tc.replicateImmediately,
- w: &stdout,
+ args := []string{
+ "-virtual-storage", virtualStorageName,
+ "-repository", tc.relativePath,
+ "-authoritative-storage", authoritativeStorage,
+ }
+ if tc.replicateImmediately {
+ args = append(args, "-replicate-immediately")
}
+ stdout, err := runCmd(t, args)
+ require.NoError(t, err)
- require.NoError(t, addRepoCmd.Exec(flag.NewFlagSet("", flag.PanicOnError), conf))
as := datastore.NewAssignmentStore(db, conf.StorageNames())
repositoryID, err := repoDS.GetRepositoryID(ctx, virtualStorageName, tc.relativePath)
@@ -206,14 +255,20 @@ func TestAddRepository_Exec(t *testing.T) {
assignments, err := as.GetHostAssignments(ctx, virtualStorageName, repositoryID)
require.NoError(t, err)
- require.Len(t, assignments, 2)
+ if tc.repositoryExists {
+ require.Len(t, assignments, 1)
+ } else {
+ require.Len(t, assignments, 2)
+ assert.Contains(t, assignments, g2Cfg.Storages[0].Name)
+ }
assert.Contains(t, assignments, g1Cfg.Storages[0].Name)
- assert.Contains(t, assignments, g2Cfg.Storages[0].Name)
exists, err = repoDS.RepositoryExists(ctx, virtualStorageName, tc.relativePath)
require.NoError(t, err)
assert.True(t, exists)
- assert.Contains(t, stdout.String(), tc.expectedOutput)
+ for _, expectedOutput := range tc.expectedOutput {
+ assert.Contains(t, stdout, expectedOutput)
+ }
if !tc.replicateImmediately {
queue := datastore.NewPostgresReplicationEventQueue(db)
@@ -226,54 +281,6 @@ func TestAddRepository_Exec(t *testing.T) {
}
})
- t.Run("repository does not exist", func(t *testing.T) {
- relativePath := "path/to/test/repo_1"
-
- cmd := &trackRepository{
- w: &bytes.Buffer{},
- logger: testhelper.NewDiscardingLogger(t),
- virtualStorage: "praefect",
- relativePath: relativePath,
- authoritativeStorage: authoritativeStorage,
- }
-
- assert.ErrorIs(t, cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), conf), errAuthoritativeRepositoryNotExist)
- })
-
- t.Run("records already exist", func(t *testing.T) {
- relativePath := "path/to/test/repo_2"
-
- require.NoError(t, createRepoThroughGitaly1(relativePath))
- require.DirExists(t, filepath.Join(g1Cfg.Storages[0].Path, relativePath))
- require.NoDirExists(t, filepath.Join(g2Cfg.Storages[0].Path, relativePath))
-
- ds := datastore.NewPostgresRepositoryStore(db, conf.StorageNames())
- id, err := ds.ReserveRepositoryID(ctx, virtualStorageName, relativePath)
- require.NoError(t, err)
- require.NoError(t, ds.CreateRepository(
- ctx,
- id,
- virtualStorageName,
- relativePath,
- relativePath,
- g1Cfg.Storages[0].Name,
- nil,
- nil,
- true,
- true,
- ))
-
- cmd := &trackRepository{
- w: &bytes.Buffer{},
- logger: testhelper.NewDiscardingLogger(t),
- virtualStorage: virtualStorageName,
- relativePath: relativePath,
- authoritativeStorage: authoritativeStorage,
- }
-
- assert.NoError(t, cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), conf))
- })
-
t.Run("replication event exists", func(t *testing.T) {
relativePath := "path/to/test/repo_3"
@@ -281,19 +288,20 @@ func TestAddRepository_Exec(t *testing.T) {
require.DirExists(t, filepath.Join(g1Cfg.Storages[0].Path, relativePath))
require.NoDirExists(t, filepath.Join(g2Cfg.Storages[0].Path, relativePath))
- var stdout bytes.Buffer
- cmd := &trackRepository{
- w: &stdout,
- logger: testhelper.NewDiscardingLogger(t),
- virtualStorage: virtualStorageName,
- relativePath: relativePath,
- authoritativeStorage: authoritativeStorage,
- }
-
- assert.NoError(t, cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), conf))
+ _, err := runCmd(t, []string{
+ "-virtual-storage", virtualStorageName,
+ "-repository", relativePath,
+ "-authoritative-storage", authoritativeStorage,
+ })
+ require.NoError(t, err)
// running the command twice means we try creating the replication event
// again, which should log the duplicate but not break the flow.
- assert.NoError(t, cmd.Exec(flag.NewFlagSet("", flag.PanicOnError), conf))
- assert.Contains(t, stdout.String(), "replication event queue already has similar entry: replication event \"\" -> \"praefect\" -> \"gitaly-2\" -> \"path/to/test/repo_3\" already exists.")
+ stdout, err := runCmd(t, []string{
+ "-virtual-storage", virtualStorageName,
+ "-repository", relativePath,
+ "-authoritative-storage", authoritativeStorage,
+ })
+ require.NoError(t, err)
+ assert.Contains(t, stdout, "replication event queue already has similar entry: replication event \"\" -> \"praefect\" -> \"gitaly-2\" -> \"path/to/test/repo_3\" already exists.")
})
}
diff --git a/internal/cli/praefect/subcmd_verify.go b/internal/cli/praefect/subcmd_verify.go
index 544353e2c..5e40e8a91 100644
--- a/internal/cli/praefect/subcmd_verify.go
+++ b/internal/cli/praefect/subcmd_verify.go
@@ -1,74 +1,93 @@
package praefect
import (
- "context"
"errors"
- "flag"
"fmt"
- "io"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
+ "github.com/urfave/cli/v2"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
const verifyCmdName = "verify"
-type verifySubcommand struct {
- stdout io.Writer
- repositoryID int64
- virtualStorage string
- storage string
-}
-
-func newVerifySubcommand(stdout io.Writer) *verifySubcommand {
- return &verifySubcommand{stdout: stdout}
-}
-
-func (cmd *verifySubcommand) FlagSet() *flag.FlagSet {
- fs := flag.NewFlagSet(metadataCmdName, flag.ContinueOnError)
- fs.Int64Var(&cmd.repositoryID, "repository-id", 0, "the id of the repository to verify")
- fs.StringVar(&cmd.virtualStorage, "virtual-storage", "", "the virtual storage to verify")
- fs.StringVar(&cmd.storage, "storage", "", "the storage to verify")
- return fs
+func newVerifyCommand() *cli.Command {
+ return &cli.Command{
+ Name: verifyCmdName,
+ Usage: "marks a discrete repository, or repositories of a storage, or repositories of a virtual storage to be verified",
+ Description: "The command marks a single repository if 'repository-id' flag is provided or a batch of\n" +
+ "repositories that belong to a particular storage or virtual storage to be checked they exist.\n" +
+ "The repository existence is confirmed if repository exists on the disk. That verification operation\n" +
+ "runs in background and executes verification asynchronously.",
+ HideHelpCommand: true,
+ Action: verifyAction,
+ Flags: []cli.Flag{
+ &cli.Int64Flag{
+ Name: "repository-id",
+ Usage: "the id of the repository to verify",
+ },
+ &cli.StringFlag{
+ Name: paramVirtualStorage,
+ Usage: "the virtual storage to verify",
+ },
+ &cli.StringFlag{
+ Name: "storage",
+ Usage: "the storage to verify",
+ },
+ },
+ Before: func(ctx *cli.Context) error {
+ if ctx.Args().Present() {
+ _ = cli.ShowSubcommandHelp(ctx)
+ return cli.Exit(unexpectedPositionalArgsError{Command: ctx.Command.Name}, 1)
+ }
+ return nil
+ },
+ }
}
-func (cmd *verifySubcommand) Exec(flags *flag.FlagSet, cfg config.Config) error {
- if flags.NArg() > 0 {
- return unexpectedPositionalArgsError{Command: flags.Name()}
+func verifyAction(appCtx *cli.Context) error {
+ logger := log.Default()
+ conf, err := getConfig(logger, appCtx.String(configFlagName))
+ if err != nil {
+ return err
}
+ repositoryID := appCtx.Int64("repository-id")
+ virtualStorage := appCtx.String(paramVirtualStorage)
+ storage := appCtx.String("storage")
+
var request gitalypb.MarkUnverifiedRequest
switch {
- case cmd.repositoryID != 0:
- if cmd.virtualStorage != "" || cmd.storage != "" {
+ case repositoryID != 0:
+ if virtualStorage != "" || storage != "" {
return errors.New("virtual storage and storage can't be provided with a repository ID")
}
- request.Selector = &gitalypb.MarkUnverifiedRequest_RepositoryId{RepositoryId: cmd.repositoryID}
- case cmd.storage != "":
- if cmd.virtualStorage == "" {
+ request.Selector = &gitalypb.MarkUnverifiedRequest_RepositoryId{RepositoryId: repositoryID}
+ case storage != "":
+ if virtualStorage == "" {
return errors.New("virtual storage must be passed with storage")
}
request.Selector = &gitalypb.MarkUnverifiedRequest_Storage_{
Storage: &gitalypb.MarkUnverifiedRequest_Storage{
- VirtualStorage: cmd.virtualStorage,
- Storage: cmd.storage,
+ VirtualStorage: virtualStorage,
+ Storage: storage,
},
}
- case cmd.virtualStorage != "":
- request.Selector = &gitalypb.MarkUnverifiedRequest_VirtualStorage{VirtualStorage: cmd.virtualStorage}
+ case virtualStorage != "":
+ request.Selector = &gitalypb.MarkUnverifiedRequest_VirtualStorage{VirtualStorage: virtualStorage}
default:
return errors.New("(repository id), (virtual storage) or (virtual storage, storage) required")
}
- nodeAddr, err := getNodeAddress(cfg)
+ nodeAddr, err := getNodeAddress(conf)
if err != nil {
return fmt.Errorf("get node address: %w", err)
}
- ctx := context.TODO()
- conn, err := subCmdDial(ctx, nodeAddr, cfg.Auth.Token, defaultDialTimeout)
+ ctx := appCtx.Context
+ conn, err := subCmdDial(ctx, nodeAddr, conf.Auth.Token, defaultDialTimeout)
if err != nil {
return fmt.Errorf("dial: %w", err)
}
@@ -79,7 +98,7 @@ func (cmd *verifySubcommand) Exec(flags *flag.FlagSet, cfg config.Config) error
return fmt.Errorf("verify replicas: %w", err)
}
- fmt.Fprintf(cmd.stdout, "%d replicas marked unverified\n", response.GetReplicasMarked())
+ fmt.Fprintf(appCtx.App.Writer, "%d replicas marked unverified\n", response.GetReplicasMarked())
return nil
}
diff --git a/internal/cli/praefect/subcmd_verify_test.go b/internal/cli/praefect/subcmd_verify_test.go
index 19a1e5d9d..901579f17 100644
--- a/internal/cli/praefect/subcmd_verify_test.go
+++ b/internal/cli/praefect/subcmd_verify_test.go
@@ -4,9 +4,11 @@ import (
"bytes"
"errors"
"fmt"
+ "io"
"testing"
"github.com/stretchr/testify/require"
+ "github.com/urfave/cli/v2"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/info"
@@ -50,6 +52,11 @@ func TestVerifySubcommand(t *testing.T) {
expectedState state
}{
{
+ desc: "positional arguments",
+ args: []string{"positional-arg"},
+ error: cli.Exit(unexpectedPositionalArgsError{Command: "verify"}, 1),
+ },
+ {
desc: "no selector given",
error: errors.New("(repository id), (virtual storage) or (virtual storage, storage) required"),
expectedState: startingState,
@@ -187,12 +194,36 @@ func TestVerifySubcommand(t *testing.T) {
`)
require.NoError(t, err)
- stdout := &bytes.Buffer{}
- cmd := newVerifySubcommand(stdout)
+ conf := config.Config{
+ SocketPath: ln.Addr().String(),
+ VirtualStorages: []*config.VirtualStorage{
+ {
+ Name: "vs",
+ Nodes: []*config.Node{
+ {Address: "stub", Storage: "st"},
+ },
+ },
+ },
+ }
+ confPath := writeConfigToFile(t, conf)
- fs := cmd.FlagSet()
- require.NoError(t, fs.Parse(tc.args))
- err = cmd.Exec(fs, config.Config{SocketPath: ln.Addr().String()})
+ var stdout bytes.Buffer
+ app := cli.App{
+ Reader: bytes.NewReader(nil),
+ Writer: &stdout,
+ ErrWriter: io.Discard,
+ HideHelpCommand: true,
+ Commands: []*cli.Command{
+ newVerifyCommand(),
+ },
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "config",
+ Value: confPath,
+ },
+ },
+ }
+ err = app.Run(append([]string{progname, verifyCmdName}, tc.args...))
testhelper.RequireGrpcError(t, tc.error, err)
if tc.error != nil {
return
diff --git a/internal/command/command.go b/internal/command/command.go
index 4af839fbf..ea688a156 100644
--- a/internal/command/command.go
+++ b/internal/command/command.go
@@ -20,7 +20,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/command/commandcounter"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
labkittracing "gitlab.com/gitlab-org/labkit/tracing"
)
diff --git a/internal/command/command_test.go b/internal/command/command_test.go
index 8eda53261..dd23c85d6 100644
--- a/internal/command/command_test.go
+++ b/internal/command/command_test.go
@@ -21,7 +21,11 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/cgroups"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/protobuf/types/known/durationpb"
)
func TestNew_environment(t *testing.T) {
@@ -196,7 +200,18 @@ func TestNew_spawnTimeout(t *testing.T) {
// And after some time we expect that spawning of the command fails due to the configured
// timeout.
- require.Equal(t, fmt.Errorf("process spawn timed out after 200ms"), <-errCh)
+ err := <-errCh
+ var structErr structerr.Error
+ require.ErrorAs(t, err, &structErr)
+ details := structErr.Details()
+ require.Len(t, details, 1)
+
+ limitErr, ok := details[0].(*gitalypb.LimitError)
+ require.True(t, ok)
+
+ testhelper.RequireGrpcCode(t, err, codes.ResourceExhausted)
+ require.Equal(t, "process spawn timed out after 200ms", limitErr.ErrorMessage)
+ require.Equal(t, durationpb.New(0), limitErr.RetryAfter)
}
func TestCommand_Wait_contextCancellationKillsCommand(t *testing.T) {
diff --git a/internal/command/spawntoken.go b/internal/command/spawntoken.go
index b49a32192..2b0065bf5 100644
--- a/internal/command/spawntoken.go
+++ b/internal/command/spawntoken.go
@@ -5,15 +5,15 @@ import (
"fmt"
"time"
- "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
"github.com/kelseyhightower/envconfig"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+ "google.golang.org/protobuf/types/known/durationpb"
)
-const logDurationThreshold = 5 * time.Millisecond
-
var (
spawnTokens chan struct{}
spawnConfig SpawnConfig
@@ -63,31 +63,32 @@ func getSpawnToken(ctx context.Context) (putToken func(), err error) {
select {
case spawnTokens <- struct{}{}:
- logTime(ctx, start, "spawn token acquired")
+ recordTime(ctx, start, "")
return func() {
<-spawnTokens
}, nil
case <-time.After(spawnConfig.Timeout):
- logTime(ctx, start, "spawn token timeout")
+ recordTime(ctx, start, "spawn token timeout")
spawnTimeoutCount.Inc()
- return nil, fmt.Errorf("process spawn timed out after %v", spawnConfig.Timeout)
+ msg := fmt.Sprintf("process spawn timed out after %v", spawnConfig.Timeout)
+ return nil, structerr.NewResourceExhausted(msg).WithDetail(&gitalypb.LimitError{
+ ErrorMessage: msg,
+ RetryAfter: durationpb.New(0),
+ })
case <-ctx.Done():
return nil, ctx.Err()
}
}
-func logTime(ctx context.Context, start time.Time, msg string) {
+func recordTime(ctx context.Context, start time.Time, msg string) {
delta := time.Since(start)
if stats := StatsFromContext(ctx); stats != nil {
stats.RecordSum("command.spawn_token_wait_ms", int(delta.Milliseconds()))
+ if len(msg) != 0 {
+ stats.RecordMetadata("command.spawn_token_error", msg)
+ }
}
-
- if delta < logDurationThreshold {
- return
- }
-
- ctxlogrus.Extract(ctx).WithField("spawn_queue_ms", delta.Seconds()*1000).Info(msg)
}
diff --git a/internal/command/spawntoken_test.go b/internal/command/spawntoken_test.go
index 014802fff..62f534b7f 100644
--- a/internal/command/spawntoken_test.go
+++ b/internal/command/spawntoken_test.go
@@ -2,12 +2,19 @@ package command
import (
"testing"
+ "time"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/protobuf/types/known/durationpb"
)
func TestGetSpawnToken_CommandStats(t *testing.T) {
+ t.Parallel()
+
ctx := testhelper.Context(t)
ctx = InitContextStats(ctx)
@@ -19,3 +26,41 @@ func TestGetSpawnToken_CommandStats(t *testing.T) {
require.NotNil(t, stats)
require.Contains(t, stats.Fields(), "command.spawn_token_wait_ms")
}
+
+// This test modifies a global config, hence should never run in parallel
+func TestGetSpawnToken_CommandStats_timeout(t *testing.T) {
+ priorTimeout := spawnConfig.Timeout
+ priorSpawnTokens := spawnTokens
+
+ spawnConfig.Timeout = 1 * time.Millisecond
+ spawnTokens = make(chan struct{}, 1)
+ spawnTokens <- struct{}{}
+ defer func() {
+ spawnConfig.Timeout = priorTimeout
+ spawnTokens = priorSpawnTokens
+ }()
+
+ ctx := testhelper.Context(t)
+ ctx = InitContextStats(ctx)
+
+ _, err := getSpawnToken(ctx)
+
+ var structErr structerr.Error
+ require.ErrorAs(t, err, &structErr)
+ details := structErr.Details()
+ require.Len(t, details, 1)
+
+ limitErr, ok := details[0].(*gitalypb.LimitError)
+ require.True(t, ok)
+
+ testhelper.RequireGrpcCode(t, err, codes.ResourceExhausted)
+ require.Equal(t, "process spawn timed out after 1ms", limitErr.ErrorMessage)
+ require.Equal(t, durationpb.New(0), limitErr.RetryAfter)
+
+ stats := StatsFromContext(ctx)
+ require.NotNil(t, stats)
+ fields := stats.Fields()
+
+ require.GreaterOrEqual(t, fields["command.spawn_token_wait_ms"], 0)
+ require.Equal(t, fields["command.spawn_token_error"], "spawn token timeout")
+}
diff --git a/internal/metadata/featureflag/context.go b/internal/featureflag/context.go
index caa0f0e48..caa0f0e48 100644
--- a/internal/metadata/featureflag/context.go
+++ b/internal/featureflag/context.go
diff --git a/internal/metadata/featureflag/context_test.go b/internal/featureflag/context_test.go
index 9dd864373..b41128d70 100644
--- a/internal/metadata/featureflag/context_test.go
+++ b/internal/featureflag/context_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
- gitaly_metadata "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ gitaly_metadata "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"google.golang.org/grpc/metadata"
)
diff --git a/internal/metadata/featureflag/featureflag.go b/internal/featureflag/featureflag.go
index 0ccf7ba31..0ccf7ba31 100644
--- a/internal/metadata/featureflag/featureflag.go
+++ b/internal/featureflag/featureflag.go
diff --git a/internal/metadata/featureflag/featureflag_test.go b/internal/featureflag/featureflag_test.go
index 4246f0a1d..4246f0a1d 100644
--- a/internal/metadata/featureflag/featureflag_test.go
+++ b/internal/featureflag/featureflag_test.go
diff --git a/internal/metadata/featureflag/ff_fix_routing_with_additional_repository.go b/internal/featureflag/ff_fix_routing_with_additional_repository.go
index 4d01587e0..2cd2b63dd 100644
--- a/internal/metadata/featureflag/ff_fix_routing_with_additional_repository.go
+++ b/internal/featureflag/ff_fix_routing_with_additional_repository.go
@@ -8,6 +8,6 @@ package featureflag
var FixRoutingWithAdditionalRepository = NewFeatureFlag(
"fix_routing_with_additional_repository",
"v16.0.0",
- "",
+ "https://gitlab.com/gitlab-org/gitaly/-/issues/5134",
false,
)
diff --git a/internal/metadata/featureflag/ff_geometric_repacking.go b/internal/featureflag/ff_geometric_repacking.go
index 8665b9d21..8665b9d21 100644
--- a/internal/metadata/featureflag/ff_geometric_repacking.go
+++ b/internal/featureflag/ff_geometric_repacking.go
diff --git a/internal/metadata/featureflag/ff_localrepo_read_object_cached.go b/internal/featureflag/ff_localrepo_read_object_cached.go
index 40e60d1f1..40e60d1f1 100644
--- a/internal/metadata/featureflag/ff_localrepo_read_object_cached.go
+++ b/internal/featureflag/ff_localrepo_read_object_cached.go
diff --git a/internal/metadata/featureflag/ff_pack_objects_limiting_remote_ip.go b/internal/featureflag/ff_pack_objects_limiting_remote_ip.go
index e4d9a5c1e..e4d9a5c1e 100644
--- a/internal/metadata/featureflag/ff_pack_objects_limiting_remote_ip.go
+++ b/internal/featureflag/ff_pack_objects_limiting_remote_ip.go
diff --git a/internal/metadata/featureflag/ff_run_cmd_in_cgroup.go b/internal/featureflag/ff_run_cmd_in_cgroup.go
index 356bae752..356bae752 100644
--- a/internal/metadata/featureflag/ff_run_cmd_in_cgroup.go
+++ b/internal/featureflag/ff_run_cmd_in_cgroup.go
diff --git a/internal/git/catfile/cache.go b/internal/git/catfile/cache.go
index 63fd357bb..69bebbec1 100644
--- a/internal/git/catfile/cache.go
+++ b/internal/git/catfile/cache.go
@@ -11,8 +11,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
"gitlab.com/gitlab-org/labkit/correlation"
)
diff --git a/internal/git/catfile/object_info_reader_test.go b/internal/git/catfile/object_info_reader_test.go
index c21845d37..ae2ea6b29 100644
--- a/internal/git/catfile/object_info_reader_test.go
+++ b/internal/git/catfile/object_info_reader_test.go
@@ -230,12 +230,10 @@ func TestObjectInfoReader_queue(t *testing.T) {
commitInfo := ObjectInfo{
Oid: commitOID,
Type: "commit",
- Size: func() int64 {
- if gittest.ObjectHashIsSHA256() {
- return 201
- }
- return 177
- }(),
+ Size: gittest.ObjectHashDependent(t, map[string]int64{
+ "sha1": 177,
+ "sha256": 201,
+ }),
Format: gittest.DefaultObjectHash.Format,
}
diff --git a/internal/git/command_factory_cgroup_test.go b/internal/git/command_factory_cgroup_test.go
index 6336de8f0..39404db23 100644
--- a/internal/git/command_factory_cgroup_test.go
+++ b/internal/git/command_factory_cgroup_test.go
@@ -6,9 +6,9 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/cgroups"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
)
diff --git a/internal/git/command_options.go b/internal/git/command_options.go
index 2fae98a73..e30ff1a45 100644
--- a/internal/git/command_options.go
+++ b/internal/git/command_options.go
@@ -9,9 +9,9 @@ import (
"strings"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/x509"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/git/execution_environment.go b/internal/git/execution_environment.go
index f93132eb0..504dd7c68 100644
--- a/internal/git/execution_environment.go
+++ b/internal/git/execution_environment.go
@@ -9,8 +9,8 @@ import (
"path/filepath"
"github.com/sirupsen/logrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"golang.org/x/sys/unix"
)
diff --git a/internal/git/gitpipe/catfile_info.go b/internal/git/gitpipe/catfile_info.go
index 537c17e2d..8a25cb5d1 100644
--- a/internal/git/gitpipe/catfile_info.go
+++ b/internal/git/gitpipe/catfile_info.go
@@ -80,10 +80,10 @@ func CatfileInfo(
requestChan := make(chan catfileInfoRequest, 32)
go func() {
defer func() {
- close(requestChan)
if atomic.AddInt32(&queueRefcount, -1) == 0 {
queueCleanup()
}
+ close(requestChan)
}()
var i int64
@@ -132,10 +132,10 @@ func CatfileInfo(
resultChan := make(chan CatfileInfoResult)
go func() {
defer func() {
- close(resultChan)
if atomic.AddInt32(&queueRefcount, -1) == 0 {
queueCleanup()
}
+ close(resultChan)
}()
// It's fine to iterate over the request channel without paying attention to
diff --git a/internal/git/gitpipe/catfile_info_test.go b/internal/git/gitpipe/catfile_info_test.go
index 624c3b041..e0e51054d 100644
--- a/internal/git/gitpipe/catfile_info_test.go
+++ b/internal/git/gitpipe/catfile_info_test.go
@@ -75,7 +75,7 @@ func TestCatfileInfo(t *testing.T) {
{OID: blobID, ObjectName: []byte("branch-test.txt")},
},
expectedResults: []CatfileInfoResult{
- {ObjectInfo: &catfile.ObjectInfo{Oid: treeID, Type: "tree", Size: hashDependentObjectSize(43, 55), Format: gittest.DefaultObjectHash.Format}},
+ {ObjectInfo: &catfile.ObjectInfo{Oid: treeID, Type: "tree", Size: hashDependentObjectSize(t, 43, 55), Format: gittest.DefaultObjectHash.Format}},
{ObjectInfo: &catfile.ObjectInfo{Oid: blobID, Type: "blob", Size: 8, Format: gittest.DefaultObjectHash.Format}, ObjectName: []byte("branch-test.txt")},
},
},
@@ -277,6 +277,7 @@ func TestCatfileInfo(t *testing.T) {
// We now consume all the input of the iterator.
require.True(t, it.Next())
require.False(t, it.Next())
+ require.NoError(t, it.Err())
// Which means that the queue should now be unused, so we can again use it.
_, err = CatfileInfo(ctx, objectInfoReader, NewRevisionIterator(ctx, input))
@@ -306,8 +307,8 @@ func TestCatfileInfoAllObjects(t *testing.T) {
{ObjectInfo: &catfile.ObjectInfo{Oid: blob1, Type: "blob", Size: 6, Format: gittest.DefaultObjectHash.Format}},
{ObjectInfo: &catfile.ObjectInfo{Oid: blob2, Type: "blob", Size: 6, Format: gittest.DefaultObjectHash.Format}},
{ObjectInfo: &catfile.ObjectInfo{Oid: gittest.DefaultObjectHash.EmptyTreeOID, Type: "tree", Size: 0, Format: gittest.DefaultObjectHash.Format}},
- {ObjectInfo: &catfile.ObjectInfo{Oid: tree, Type: "tree", Size: hashDependentObjectSize(34, 46), Format: gittest.DefaultObjectHash.Format}},
- {ObjectInfo: &catfile.ObjectInfo{Oid: commit, Type: "commit", Size: hashDependentObjectSize(177, 201), Format: gittest.DefaultObjectHash.Format}},
+ {ObjectInfo: &catfile.ObjectInfo{Oid: tree, Type: "tree", Size: hashDependentObjectSize(t, 34, 46), Format: gittest.DefaultObjectHash.Format}},
+ {ObjectInfo: &catfile.ObjectInfo{Oid: commit, Type: "commit", Size: hashDependentObjectSize(t, 177, 201), Format: gittest.DefaultObjectHash.Format}},
}
t.Run("successful", func(t *testing.T) {
diff --git a/internal/git/gitpipe/catfile_object_test.go b/internal/git/gitpipe/catfile_object_test.go
index 81977fa18..b53d86aea 100644
--- a/internal/git/gitpipe/catfile_object_test.go
+++ b/internal/git/gitpipe/catfile_object_test.go
@@ -71,11 +71,11 @@ func TestCatfileObject(t *testing.T) {
{
desc: "revlist result with object names",
catfileInfoInputs: []CatfileInfoResult{
- {ObjectInfo: &catfile.ObjectInfo{Oid: treeID, Type: "tree", Size: hashDependentObjectSize(43, 55)}},
+ {ObjectInfo: &catfile.ObjectInfo{Oid: treeID, Type: "tree", Size: hashDependentObjectSize(t, 43, 55)}},
{ObjectInfo: &catfile.ObjectInfo{Oid: blobID, Type: "blob", Size: 59}, ObjectName: []byte("branch-test.txt")},
},
expectedResults: []CatfileObjectResult{
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: treeID, Type: "tree", Size: hashDependentObjectSize(43, 55)}}},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: treeID, Type: "tree", Size: hashDependentObjectSize(t, 43, 55)}}},
{Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: blobID, Type: "blob", Size: 8}}, ObjectName: []byte("branch-test.txt")},
},
},
diff --git a/internal/git/gitpipe/pipeline_test.go b/internal/git/gitpipe/pipeline_test.go
index 4d2762b89..b108fcb03 100644
--- a/internal/git/gitpipe/pipeline_test.go
+++ b/internal/git/gitpipe/pipeline_test.go
@@ -111,9 +111,9 @@ func TestPipeline_revlist(t *testing.T) {
WithObjects(),
},
expectedResults: []CatfileObjectResult{
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: tree, Type: "tree", Size: hashDependentObjectSize(66, 90)}}},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: tree, Type: "tree", Size: hashDependentObjectSize(t, 66, 90)}}},
{Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: blobB, Type: "blob", Size: 1}}, ObjectName: []byte("blob")},
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: subtree, Type: "tree", Size: hashDependentObjectSize(35, 47)}}, ObjectName: []byte("subtree")},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: subtree, Type: "tree", Size: hashDependentObjectSize(t, 35, 47)}}, ObjectName: []byte("subtree")},
{Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: blobA, Type: "blob", Size: 6}}, ObjectName: []byte("subtree/subblob")},
},
},
@@ -152,10 +152,10 @@ func TestPipeline_revlist(t *testing.T) {
WithObjects(),
},
expectedResults: []CatfileObjectResult{
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: commitB, Type: "commit", Size: hashDependentObjectSize(225, 273)}}},
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: tree, Type: "tree", Size: hashDependentObjectSize(66, 90)}}},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: commitB, Type: "commit", Size: hashDependentObjectSize(t, 225, 273)}}},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: tree, Type: "tree", Size: hashDependentObjectSize(t, 66, 90)}}},
{Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: blobB, Type: "blob", Size: 1}}, ObjectName: []byte("blob")},
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: subtree, Type: "tree", Size: hashDependentObjectSize(35, 47)}}, ObjectName: []byte("subtree")},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: subtree, Type: "tree", Size: hashDependentObjectSize(t, 35, 47)}}, ObjectName: []byte("subtree")},
{Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: blobA, Type: "blob", Size: 6}}, ObjectName: []byte("subtree/subblob")},
},
},
@@ -166,7 +166,7 @@ func TestPipeline_revlist(t *testing.T) {
commitB.String(),
},
expectedResults: []CatfileObjectResult{
- {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: commitB, Type: "commit", Size: hashDependentObjectSize(225, 273)}}},
+ {Object: &catfile.Object{ObjectInfo: catfile.ObjectInfo{Oid: commitB, Type: "commit", Size: hashDependentObjectSize(t, 225, 273)}}},
},
},
{
diff --git a/internal/git/gitpipe/testhelper_test.go b/internal/git/gitpipe/testhelper_test.go
index ba13f75c2..df850aec7 100644
--- a/internal/git/gitpipe/testhelper_test.go
+++ b/internal/git/gitpipe/testhelper_test.go
@@ -51,9 +51,9 @@ func (ch *chanObjectIterator) ObjectName() []byte {
return []byte("idontcare")
}
-func hashDependentObjectSize(sha1Size, sha256Size int64) int64 {
- if gittest.ObjectHashIsSHA256() {
- return sha256Size
- }
- return sha1Size
+func hashDependentObjectSize(tb testing.TB, sha1Size, sha256Size int64) int64 {
+ return gittest.ObjectHashDependent(tb, map[string]int64{
+ "sha1": sha1Size,
+ "sha256": sha256Size,
+ })
}
diff --git a/internal/git/gittest/objects.go b/internal/git/gittest/objects.go
index 65d2362ee..e39611d21 100644
--- a/internal/git/gittest/objects.go
+++ b/internal/git/gittest/objects.go
@@ -20,6 +20,15 @@ func ObjectHashIsSHA256() bool {
return DefaultObjectHash.EmptyTreeOID == git.ObjectHashSHA256.EmptyTreeOID
}
+// ObjectHashDependent returns the value from the given map that is associated with the default
+// object hash (e.g. "sha1", "sha256"). Fails in case the map doesn't contain the current object
+// hash.
+func ObjectHashDependent[T any](tb testing.TB, valuesByObjectHash map[string]T) T {
+ tb.Helper()
+ require.Contains(tb, valuesByObjectHash, DefaultObjectHash.Format)
+ return valuesByObjectHash[DefaultObjectHash.Format]
+}
+
// ListObjects returns a list of all object IDs in the repository.
func ListObjects(tb testing.TB, cfg config.Cfg, repoPath string) []git.ObjectID {
tb.Helper()
diff --git a/internal/git/hooks_options.go b/internal/git/hooks_options.go
index de28cab68..41002bede 100644
--- a/internal/git/hooks_options.go
+++ b/internal/git/hooks_options.go
@@ -5,11 +5,11 @@ import (
"errors"
"fmt"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
labkittracing "gitlab.com/gitlab-org/labkit/tracing"
diff --git a/internal/git/hooks_options_test.go b/internal/git/hooks_options_test.go
index 3dfefd7f2..d96530a64 100644
--- a/internal/git/hooks_options_test.go
+++ b/internal/git/hooks_options_test.go
@@ -8,7 +8,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
grpcmetadata "google.golang.org/grpc/metadata"
diff --git a/internal/git/hooks_payload.go b/internal/git/hooks_payload.go
index 7bcf2acc7..2dfd8f15d 100644
--- a/internal/git/hooks_payload.go
+++ b/internal/git/hooks_payload.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/protobuf/encoding/protojson"
diff --git a/internal/git/hooks_payload_test.go b/internal/git/hooks_payload_test.go
index c733d8e7e..e73e755a6 100644
--- a/internal/git/hooks_payload_test.go
+++ b/internal/git/hooks_payload_test.go
@@ -5,9 +5,9 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
diff --git a/internal/git/housekeeping/clean_stale_data.go b/internal/git/housekeeping/clean_stale_data.go
index 3e7908236..a21b4367e 100644
--- a/internal/git/housekeeping/clean_stale_data.go
+++ b/internal/git/housekeeping/clean_stale_data.go
@@ -15,6 +15,7 @@ import (
log "github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
@@ -40,10 +41,56 @@ var lockfiles = []string{
"objects/info/commit-graphs/commit-graph-chain.lock",
}
-type staleFileFinderFn func(context.Context, string) ([]string, error)
+type (
+ findStaleFileFunc func(context.Context, string) ([]string, error)
+ cleanupRepoFunc func(context.Context, *localrepo.Repo) (int, error)
+ cleanupRepoWithTxManagerFunc func(context.Context, *localrepo.Repo, transaction.Manager) (int, error)
+)
+
+// CleanStaleDataConfig is the configuration for running CleanStaleData. It is used to define
+// the different types of cleanups we want to run.
+type CleanStaleDataConfig struct {
+ staleFileFinders map[string]findStaleFileFunc
+ repoCleanups map[string]cleanupRepoFunc
+ repoCleanupWithTxManagers map[string]cleanupRepoWithTxManagerFunc
+}
+
+// OnlyStaleReferenceLockCleanup returns a config which only contains a
+// stale reference lock cleaner with the provided grace period.
+func OnlyStaleReferenceLockCleanup(gracePeriod time.Duration) CleanStaleDataConfig {
+ return CleanStaleDataConfig{
+ staleFileFinders: map[string]findStaleFileFunc{
+ "reflocks": findStaleReferenceLocks(gracePeriod),
+ },
+ }
+}
-// CleanStaleData cleans up any stale data in the repository.
-func (m *RepositoryManager) CleanStaleData(ctx context.Context, repo *localrepo.Repo) error {
+// DefaultStaleDataCleanup is the default configuration for CleanStaleData
+// which contains all the cleanup functions.
+func DefaultStaleDataCleanup() CleanStaleDataConfig {
+ return CleanStaleDataConfig{
+ staleFileFinders: map[string]findStaleFileFunc{
+ "objects": findTemporaryObjects,
+ "locks": findStaleLockfiles,
+ "refs": findBrokenLooseReferences,
+ "reflocks": findStaleReferenceLocks(referenceLockfileGracePeriod),
+ "packfilelocks": findStalePackFileLocks,
+ "packedrefslock": findPackedRefsLock,
+ "packedrefsnew": findPackedRefsNew,
+ "serverinfo": findServerInfo,
+ },
+ repoCleanups: map[string]cleanupRepoFunc{
+ "refsemptydir": removeRefEmptyDirs,
+ "configsections": pruneEmptyConfigSections,
+ },
+ repoCleanupWithTxManagers: map[string]cleanupRepoWithTxManagerFunc{
+ "configkeys": removeUnnecessaryConfig,
+ },
+ }
+}
+
+// CleanStaleData removes any stale data in the repository as per the provided configuration.
+func (m *RepositoryManager) CleanStaleData(ctx context.Context, repo *localrepo.Repo, cfg CleanStaleDataConfig) error {
span, ctx := tracing.StartSpanIfHasParent(ctx, "housekeeping.CleanStaleData", nil)
defer span.Finish()
@@ -71,16 +118,7 @@ func (m *RepositoryManager) CleanStaleData(ctx context.Context, repo *localrepo.
}()
var filesToPrune []string
- for staleFileType, staleFileFinder := range map[string]staleFileFinderFn{
- "objects": findTemporaryObjects,
- "locks": findStaleLockfiles,
- "refs": findBrokenLooseReferences,
- "reflocks": findStaleReferenceLocks,
- "packfilelocks": findStalePackFileLocks,
- "packedrefslock": findPackedRefsLock,
- "packedrefsnew": findPackedRefsNew,
- "serverinfo": findServerInfo,
- } {
+ for staleFileType, staleFileFinder := range cfg.staleFileFinders {
staleFiles, err := staleFileFinder(ctx, repoPath)
if err != nil {
return fmt.Errorf("housekeeping failed to find %s: %w", staleFileType, err)
@@ -100,31 +138,20 @@ func (m *RepositoryManager) CleanStaleData(ctx context.Context, repo *localrepo.
}
}
- prunedRefDirs, err := removeRefEmptyDirs(ctx, repo)
- staleDataByType["refsemptydir"] = prunedRefDirs
- if err != nil {
- return fmt.Errorf("housekeeping could not remove empty refs: %w", err)
- }
-
- unnecessaryConfigRegex := "^(http\\..+\\.extraheader|remote\\..+\\.(fetch|mirror|prune|url)|core\\.(commitgraph|sparsecheckout|splitindex))$"
- if err := repo.UnsetMatchingConfig(ctx, unnecessaryConfigRegex, m.txManager); err != nil {
- if !errors.Is(err, git.ErrNotFound) {
- return fmt.Errorf("housekeeping could not unset unnecessary config lines: %w", err)
+ for repoCleanupName, repoCleanupFn := range cfg.repoCleanups {
+ cleanupCount, err := repoCleanupFn(ctx, repo)
+ staleDataByType[repoCleanupName] = cleanupCount
+ if err != nil {
+ return fmt.Errorf("housekeeping could not perform cleanup %s: %w", repoCleanupName, err)
}
- staleDataByType["configkeys"] = 0
- } else {
- // If we didn't get an error we know that we've deleted _something_. We just set
- // this variable to `1` because we don't count how many keys we have deleted. It's
- // probably good enough: we only want to know whether we're still pruning such old
- // configuration or not, but typically don't care how many there are so that we know
- // when to delete this cleanup of legacy data.
- staleDataByType["configkeys"] = 1
}
- skippedSections, err := pruneEmptyConfigSections(ctx, repo)
- staleDataByType["configsections"] = skippedSections
- if err != nil {
- return fmt.Errorf("failed pruning empty sections: %w", err)
+ for repoCleanupName, repoCleanupFn := range cfg.repoCleanupWithTxManagers {
+ cleanupCount, err := repoCleanupFn(ctx, repo, m.txManager)
+ staleDataByType[repoCleanupName] = cleanupCount
+ if err != nil {
+ return fmt.Errorf("housekeeping could not perform cleanup (with TxManager) %s: %w", repoCleanupName, err)
+ }
}
return nil
@@ -426,47 +453,68 @@ func findBrokenLooseReferences(ctx context.Context, repoPath string) ([]string,
return brokenRefs, nil
}
-// findStaleReferenceLocks scans the refdb for stale locks for loose references.
-func findStaleReferenceLocks(ctx context.Context, repoPath string) ([]string, error) {
- var staleReferenceLocks []string
+// findStaleReferenceLocks provides a function which scans the refdb for stale locks
+// and loose references against the provided grace period.
+func findStaleReferenceLocks(gracePeriod time.Duration) findStaleFileFunc {
+ return func(_ context.Context, repoPath string) ([]string, error) {
+ var staleReferenceLocks []string
- if err := filepath.WalkDir(filepath.Join(repoPath, "refs"), func(path string, dirEntry fs.DirEntry, err error) error {
- if err != nil {
- if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) {
+ if err := filepath.WalkDir(filepath.Join(repoPath, "refs"), func(path string, dirEntry fs.DirEntry, err error) error {
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) {
+ return nil
+ }
+
+ return err
+ }
+
+ if dirEntry.IsDir() {
return nil
}
- return err
- }
+ if !strings.HasSuffix(dirEntry.Name(), ".lock") {
+ return nil
+ }
- if dirEntry.IsDir() {
- return nil
- }
+ fi, err := dirEntry.Info()
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ return nil
+ }
- if !strings.HasSuffix(dirEntry.Name(), ".lock") {
- return nil
- }
+ return fmt.Errorf("statting reference lock: %w", err)
+ }
- fi, err := dirEntry.Info()
- if err != nil {
- if errors.Is(err, fs.ErrNotExist) {
+ if time.Since(fi.ModTime()) < gracePeriod {
return nil
}
- return fmt.Errorf("statting reference lock: %w", err)
+ staleReferenceLocks = append(staleReferenceLocks, path)
+ return nil
+ }); err != nil {
+ return nil, fmt.Errorf("walking refs: %w", err)
}
- if time.Since(fi.ModTime()) < referenceLockfileGracePeriod {
- return nil
+ return staleReferenceLocks, nil
+ }
+}
+
+func removeUnnecessaryConfig(ctx context.Context, repository *localrepo.Repo, txManager transaction.Manager) (int, error) {
+ unnecessaryConfigRegex := "^(http\\..+\\.extraheader|remote\\..+\\.(fetch|mirror|prune|url)|core\\.(commitgraph|sparsecheckout|splitindex))$"
+ if err := repository.UnsetMatchingConfig(ctx, unnecessaryConfigRegex, txManager); err != nil {
+ if !errors.Is(err, git.ErrNotFound) {
+ return 0, fmt.Errorf("housekeeping could not unset unnecessary config lines: %w", err)
}
- staleReferenceLocks = append(staleReferenceLocks, path)
- return nil
- }); err != nil {
- return nil, fmt.Errorf("walking refs: %w", err)
+ return 0, nil
}
- return staleReferenceLocks, nil
+ // If we didn't get an error we know that we've deleted _something_. We just set
+ // this variable to `1` because we don't count how many keys we have deleted. It's
+ // probably good enough: we only want to know whether we're still pruning such old
+ // configuration or not, but typically don't care how many there are so that we know
+ // when to delete this cleanup of legacy data.
+ return 1, nil
}
// findPackedRefsLock returns stale lockfiles for the packed-refs file.
diff --git a/internal/git/housekeeping/clean_stale_data_test.go b/internal/git/housekeeping/clean_stale_data_test.go
index bdb256021..52f5327be 100644
--- a/internal/git/housekeeping/clean_stale_data_test.go
+++ b/internal/git/housekeeping/clean_stale_data_test.go
@@ -13,10 +13,10 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
@@ -203,6 +203,26 @@ func requireCleanStaleDataMetrics(t *testing.T, m *RepositoryManager, metrics cl
require.NoError(t, testutil.CollectAndCompare(m, strings.NewReader(builder.String()), "gitaly_housekeeping_pruned_files_total"))
}
+func requireReferenceLockCleanupMetrics(t *testing.T, m *RepositoryManager, metrics cleanStaleDataMetrics) {
+ t.Helper()
+
+ var builder strings.Builder
+
+ _, err := builder.WriteString("# HELP gitaly_housekeeping_pruned_files_total Total number of files pruned\n")
+ require.NoError(t, err)
+ _, err = builder.WriteString("# TYPE gitaly_housekeeping_pruned_files_total counter\n")
+ require.NoError(t, err)
+
+ for metric, expectedValue := range map[string]int{
+ "reflocks": metrics.reflocks,
+ } {
+ _, err := builder.WriteString(fmt.Sprintf("gitaly_housekeeping_pruned_files_total{filetype=%q} %d\n", metric, expectedValue))
+ require.NoError(t, err)
+ }
+
+ require.NoError(t, testutil.CollectAndCompare(m, strings.NewReader(builder.String()), "gitaly_housekeeping_pruned_files_total"))
+}
+
func TestRepositoryManager_CleanStaleData(t *testing.T) {
t.Parallel()
testcases := []struct {
@@ -381,7 +401,7 @@ func TestRepositoryManager_CleanStaleData(t *testing.T) {
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
for _, e := range tc.entries {
e.validate(t, repoPath)
@@ -486,7 +506,7 @@ func TestRepositoryManager_CleanStaleData_references(t *testing.T) {
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
var actual []string
require.NoError(t, filepath.Walk(filepath.Join(repoPath, "refs"), func(path string, info os.FileInfo, _ error) error {
@@ -613,7 +633,7 @@ func TestRepositoryManager_CleanStaleData_emptyRefDirs(t *testing.T) {
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
for _, e := range tc.entries {
e.validate(t, repoPath)
@@ -655,7 +675,7 @@ func TestRepositoryManager_CleanStaleData_withSpecificFile(t *testing.T) {
desc string
file string
subdirs []string
- finder staleFileFinderFn
+ finder findStaleFileFunc
expectedMetrics cleanStaleDataMetrics
}{
{
@@ -738,7 +758,7 @@ func TestRepositoryManager_CleanStaleData_withSpecificFile(t *testing.T) {
repo := localrepo.NewTestRepo(t, cfg, repoProto)
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
for _, subcase := range []struct {
desc string
entry entry
@@ -782,7 +802,7 @@ func TestRepositoryManager_CleanStaleData_withSpecificFile(t *testing.T) {
require.NoError(t, err)
require.ElementsMatch(t, subcase.expectedFiles, staleFiles)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
entry.validate(t, repoPath)
})
@@ -836,7 +856,7 @@ func TestRepositoryManager_CleanStaleData_serverInfo(t *testing.T) {
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
for _, entry := range entries {
entry.validate(t, repoPath)
@@ -856,6 +876,9 @@ func TestRepositoryManager_CleanStaleData_referenceLocks(t *testing.T) {
entries []entry
expectedReferenceLocks []string
expectedMetrics cleanStaleDataMetrics
+ gracePeriod time.Duration
+ cfg CleanStaleDataConfig
+ metricsCompareFn func(t *testing.T, m *RepositoryManager, metrics cleanStaleDataMetrics)
}{
{
desc: "fresh lock is kept",
@@ -865,6 +888,26 @@ func TestRepositoryManager_CleanStaleData_referenceLocks(t *testing.T) {
f("main.lock", withAge(10*time.Minute)),
}),
},
+ gracePeriod: referenceLockfileGracePeriod,
+ cfg: DefaultStaleDataCleanup(),
+ },
+ {
+ desc: "fresh lock is deleted when grace period is low",
+ entries: []entry{
+ d("refs", []entry{
+ f("main", withAge(10*time.Minute)),
+ f("main.lock", withAge(10*time.Minute), expectDeletion),
+ }),
+ },
+ expectedReferenceLocks: []string{
+ "refs/main.lock",
+ },
+ expectedMetrics: cleanStaleDataMetrics{
+ reflocks: 1,
+ },
+ gracePeriod: time.Second,
+ cfg: OnlyStaleReferenceLockCleanup(time.Second),
+ metricsCompareFn: requireReferenceLockCleanupMetrics,
},
{
desc: "stale lock is deleted",
@@ -880,6 +923,8 @@ func TestRepositoryManager_CleanStaleData_referenceLocks(t *testing.T) {
expectedMetrics: cleanStaleDataMetrics{
reflocks: 1,
},
+ gracePeriod: referenceLockfileGracePeriod,
+ cfg: DefaultStaleDataCleanup(),
},
{
desc: "nested reference locks are deleted",
@@ -907,6 +952,8 @@ func TestRepositoryManager_CleanStaleData_referenceLocks(t *testing.T) {
expectedMetrics: cleanStaleDataMetrics{
reflocks: 3,
},
+ gracePeriod: referenceLockfileGracePeriod,
+ cfg: DefaultStaleDataCleanup(),
},
} {
tc := tc
@@ -933,19 +980,23 @@ func TestRepositoryManager_CleanStaleData_referenceLocks(t *testing.T) {
expectedReferenceLocks = append(expectedReferenceLocks, filepath.Join(repoPath, referenceLock))
}
- staleLockfiles, err := findStaleReferenceLocks(ctx, repoPath)
+ staleLockfiles, err := findStaleReferenceLocks(tc.gracePeriod)(ctx, repoPath)
require.NoError(t, err)
require.ElementsMatch(t, expectedReferenceLocks, staleLockfiles)
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, tc.cfg))
for _, e := range tc.entries {
e.validate(t, repoPath)
}
- requireCleanStaleDataMetrics(t, mgr, tc.expectedMetrics)
+ if tc.metricsCompareFn != nil {
+ tc.metricsCompareFn(t, mgr, tc.expectedMetrics)
+ } else {
+ requireCleanStaleDataMetrics(t, mgr, tc.expectedMetrics)
+ }
})
}
}
@@ -1048,7 +1099,7 @@ func TestRepositoryManager_CleanStaleData_missingRepo(t *testing.T) {
require.NoError(t, os.RemoveAll(repoPath))
- require.NoError(t, NewManager(cfg.Prometheus, nil).CleanStaleData(ctx, repo))
+ require.NoError(t, NewManager(cfg.Prometheus, nil).CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
}
func TestRepositoryManager_CleanStaleData_unsetConfiguration(t *testing.T) {
@@ -1089,7 +1140,7 @@ func TestRepositoryManager_CleanStaleData_unsetConfiguration(t *testing.T) {
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
require.Equal(t,
`[core]
repositoryformatversion = 0
@@ -1128,7 +1179,7 @@ func TestRepositoryManager_CleanStaleData_unsetConfigurationTransactional(t *tes
AuthInfo: backchannel.WithID(nil, 1234),
})
- require.NoError(t, NewManager(cfg.Prometheus, txManager).CleanStaleData(ctx, repo))
+ require.NoError(t, NewManager(cfg.Prometheus, txManager).CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
require.Equal(t, 2, len(txManager.Votes()))
configKeys := gittest.Exec(t, cfg, "-C", repoPath, "config", "--list", "--local", "--name-only")
@@ -1180,7 +1231,7 @@ func TestRepositoryManager_CleanStaleData_pruneEmptyConfigSections(t *testing.T)
mgr := NewManager(cfg.Prometheus, nil)
- require.NoError(t, mgr.CleanStaleData(ctx, repo))
+ require.NoError(t, mgr.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()))
require.Equal(t, `[core]
repositoryformatversion = 0
filemode = true
diff --git a/internal/git/housekeeping/manager.go b/internal/git/housekeeping/manager.go
index 36e26fb86..173ad06c2 100644
--- a/internal/git/housekeeping/manager.go
+++ b/internal/git/housekeeping/manager.go
@@ -14,8 +14,8 @@ import (
// Manager is a housekeeping manager. It is supposed to handle housekeeping tasks for repositories
// such as the cleanup of unneeded files and optimizations for the repository's data structures.
type Manager interface {
- // CleanStaleData removes any stale data in the repository.
- CleanStaleData(context.Context, *localrepo.Repo) error
+ // CleanStaleData removes any stale data in the repository as per the provided configuration.
+ CleanStaleData(ctx context.Context, repo *localrepo.Repo, cfg CleanStaleDataConfig) error
// OptimizeRepository optimizes the repository's data structures such that it can be more
// efficiently served.
OptimizeRepository(context.Context, *localrepo.Repo, ...OptimizeRepositoryOption) error
diff --git a/internal/git/housekeeping/optimization_strategy.go b/internal/git/housekeeping/optimization_strategy.go
index fa44476df..37775bca3 100644
--- a/internal/git/housekeeping/optimization_strategy.go
+++ b/internal/git/housekeeping/optimization_strategy.go
@@ -5,9 +5,9 @@ import (
"math"
"time"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
)
const (
@@ -62,16 +62,6 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
return false, RepackObjectsConfig{}
}
- cfg := RepackObjectsConfig{
- // We cannot write bitmaps when there are alternates as we don't have full closure
- // of all objects in the packfile. This also does not currently work with multi pack
- // indices.
- WriteBitmap: len(s.info.Alternates) == 0,
- // We want to always update the multi-pack-index while we're already at it repacking
- // some of the objects.
- WriteMultiPackIndex: true,
- }
-
// There is a bug in Git that causes geometric repacking to fail in some circumstances when
// the repository is connected to an object pool. While we're upstreaming the fix via
// https://gitlab.com/gitlab-org/git/-/issues/152 we thus disable geometric repacks in any
@@ -85,12 +75,60 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
// have backported them into Git v2.40.0.gl1. So if we detect that the current Git version
// does indeed support geometric repacking then we can enable this even when the repository
// is part of an object pool.
- canUseGeometricRepacking := len(s.info.Alternates) == 0 || s.gitVersion.GeometricRepackingSupportsAlternates()
+ canUseGeometricRepacking := len(s.info.Alternates.ObjectDirectories) == 0 || s.gitVersion.GeometricRepackingSupportsAlternates()
if canUseGeometricRepacking && featureflag.GeometricRepacking.IsEnabled(ctx) {
nonCruftPackfilesCount := s.info.Packfiles.Count - s.info.Packfiles.CruftCount
timeSinceLastFullRepack := time.Since(s.info.Packfiles.LastFullRepack)
+ fullRepackCfg := RepackObjectsConfig{
+ // We use the full-with-unreachable strategy to also pack all unreachable
+ // objects into the packfile. This only happens for object pools though,
+ // as they should never delete objects.
+ Strategy: RepackObjectsStrategyFullWithUnreachable,
+ // We cannot write bitmaps when there are alternates as we don't have full
+ // closure of all objects in the packfile.
+ WriteBitmap: len(s.info.Alternates.ObjectDirectories) == 0,
+ // We rewrite all packfiles into a single one and thus change the layout
+ // that was indexed by the multi-pack-index. We thus need to update it, as
+ // well.
+ WriteMultiPackIndex: true,
+ }
+ if !s.info.IsObjectPool {
+ // When we don't have an object pool at hand we want to be able to expire
+ // unreachable objects. We thus use cruft packs with an expiry date.
+ fullRepackCfg.Strategy = RepackObjectsStrategyFullWithCruft
+ fullRepackCfg.CruftExpireBefore = s.expireBefore
+ }
+
+ geometricRepackCfg := RepackObjectsConfig{
+ Strategy: RepackObjectsStrategyGeometric,
+ // We cannot write bitmaps when there are alternates as we don't have full
+ // closure of all objects in the packfile.
+ WriteBitmap: len(s.info.Alternates.ObjectDirectories) == 0,
+ // We're rewriting packfiles that may be part of the multi-pack-index, so we
+ // do want to update it to reflect the new layout.
+ WriteMultiPackIndex: true,
+ }
+
+ // Incremental repacks only pack unreachable objects into a new pack. As we only
+ // perform this kind of repack in the case where the overall repository structure
+ // looks good to us we try to do use the least amount of resources to update them.
+ // We thus neither update the multi-pack-index nor do we update bitmaps.
+ incrementalRepackCfg := RepackObjectsConfig{
+ Strategy: RepackObjectsStrategyIncrementalWithUnreachable,
+ WriteBitmap: false,
+ WriteMultiPackIndex: false,
+ }
+
+ // When alternative object directories have been modified since our last full repack
+ // then we have likely joined an object pool since then. This means that we'll want
+ // to perform a full repack in order to deduplicate objects that are part of the
+ // object pool.
+ if s.info.Alternates.LastModified.After(s.info.Packfiles.LastFullRepack) {
+ return true, fullRepackCfg
+ }
+
// It is mandatory for us that we perform regular full repacks in repositories so
// that we can evict objects which are unreachable into a separate cruft pack. So in
// the case where we have more than one non-cruft packfiles and the time since our
@@ -118,30 +156,14 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
// islands into account we can get rid of this condition and only do geometric
// repacks.
if nonCruftPackfilesCount > 1 && timeSinceLastFullRepack > FullRepackCooldownPeriod {
- if s.info.IsObjectPool {
- // Using cruft packs would be pointless here as we don't ever want
- // to expire unreachable objects. And we don't want to explode
- // unreachable objects into loose objects either: for one that'd be
- // inefficient, and second they'd only get soaked up by the next
- // geometric repack anyway.
- //
- // So instead, we do a full repack that appends unreachable objects
- // to the end of the new packfile.
- cfg.Strategy = RepackObjectsStrategyFullWithUnreachable
- } else {
- cfg.Strategy = RepackObjectsStrategyFullWithCruft
- cfg.CruftExpireBefore = s.expireBefore
- }
-
- return true, cfg
+ return true, fullRepackCfg
}
// In case both packfiles and loose objects are in a good state, but we don't yet
// have a multi-pack-index we perform an incremental repack to generate one. We need
// to have multi-pack-indices for the next heuristic, so it's bad if it was missing.
if !s.info.Packfiles.MultiPackIndex.Exists {
- cfg.Strategy = RepackObjectsStrategyGeometric
- return true, cfg
+ return true, geometricRepackCfg
}
// Last but not least, we also need to take into account whether new packfiles have
@@ -198,8 +220,7 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
untrackedPackfiles := s.info.Packfiles.Count - s.info.Packfiles.MultiPackIndex.PackfileCount
if untrackedPackfiles > uint64(actualLimit) {
- cfg.Strategy = RepackObjectsStrategyGeometric
- return true, cfg
+ return true, geometricRepackCfg
}
// If there are loose objects then we want to roll them up into a new packfile.
@@ -219,15 +240,52 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
// whether objects are reachable and we don't need to update any data structures
// that scale with the repository size.
if s.info.LooseObjects.Count > looseObjectLimit {
- cfg.Strategy = RepackObjectsStrategyIncrementalWithUnreachable
- cfg.WriteBitmap = false
- cfg.WriteMultiPackIndex = false
- return true, cfg
+ return true, incrementalRepackCfg
}
return false, RepackObjectsConfig{}
}
+ fullRepackCfg := RepackObjectsConfig{
+ // We use the full-with-unreachable strategy to also pack all unreachable objects
+ // into the packfile. This only happens for object pools though, as they should
+ // never delete objects.
+ //
+ // Note that this is quite inefficient, as all unreachable objects will be exploded
+ // into loose objects now. This is fixed in our geometric repacking strategy, where
+ // we append unreachable objects to the new pack.
+ Strategy: RepackObjectsStrategyFullWithLooseUnreachable,
+ // We cannot write bitmaps when there are alternates as we don't have full closure
+ // of all objects in the packfile.
+ WriteBitmap: len(s.info.Alternates.ObjectDirectories) == 0,
+ // We want to always update the multi-pack-index while we're already at it repacking
+ // some of the objects.
+ WriteMultiPackIndex: true,
+ }
+ if !s.info.IsObjectPool {
+ // When we don't have an object pool at hand we want to be able to expire
+ // unreachable objects. We thus use cruft packs with an expiry date.
+ fullRepackCfg.Strategy = RepackObjectsStrategyFullWithCruft
+ fullRepackCfg.CruftExpireBefore = s.expireBefore
+ }
+
+ incrementalRepackCfg := RepackObjectsConfig{
+ Strategy: RepackObjectsStrategyIncremental,
+ // We cannot write bitmaps when there are alternates as we don't have full closure
+ // of all objects in the packfile.
+ WriteBitmap: len(s.info.Alternates.ObjectDirectories) == 0,
+ // We want to always update the multi-pack-index while we're already at it repacking
+ // some of the objects.
+ WriteMultiPackIndex: true,
+ }
+
+ // When alternative object directories have been modified since our last full repack then we
+ // have likely joined an object pool since then. This means that we'll want to perform a
+ // full repack in order to deduplicate objects that are part of the object pool.
+ if s.info.Alternates.LastModified.After(s.info.Packfiles.LastFullRepack) {
+ return true, fullRepackCfg
+ }
+
// Whenever we do an incremental repack we create a new packfile, and as a result Git may
// have to look into every one of the packfiles to find objects. This is less efficient the
// more packfiles we have, but we cannot repack the whole repository every time either given
@@ -268,22 +326,7 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
if uint64(math.Max(lowerLimit,
math.Log(float64(s.info.Packfiles.Size/1024/1024))/math.Log(log))) <= s.info.Packfiles.Count {
-
- // Object pools should neither have unreachable objects, nor should we ever try to
- // delete any if there are some. So we disable cruft packs and expiration of them
- // for them.
- //
- // Alternatively, we could enable writing cruft packs, but never expire the objects.
- // This is left for another iteration though once we have determined that this is
- // even necessary.
- if !s.info.IsObjectPool {
- cfg.Strategy = RepackObjectsStrategyFullWithCruft
- cfg.CruftExpireBefore = s.expireBefore
- } else {
- cfg.Strategy = RepackObjectsStrategyFullWithLooseUnreachable
- }
-
- return true, cfg
+ return true, fullRepackCfg
}
// Most Git commands do not write packfiles directly, but instead write loose objects into
@@ -300,15 +343,13 @@ func (s HeuristicalOptimizationStrategy) ShouldRepackObjects(ctx context.Context
// In our case we typically want to ensure that our repositories are much better packed than
// it is necessary on the client side. We thus take a much stricter limit of 1024 objects.
if s.info.LooseObjects.Count > looseObjectLimit {
- cfg.Strategy = RepackObjectsStrategyIncremental
- return true, cfg
+ return true, incrementalRepackCfg
}
// In case both packfiles and loose objects are in a good state, but we don't yet have a
// multi-pack-index we perform an incremental repack to generate one.
if !s.info.Packfiles.MultiPackIndex.Exists {
- cfg.Strategy = RepackObjectsStrategyIncremental
- return true, cfg
+ return true, incrementalRepackCfg
}
return false, RepackObjectsConfig{}
@@ -436,7 +477,7 @@ func NewEagerOptimizationStrategy(info stats.RepositoryInfo) EagerOptimizationSt
// not have any alternates.
func (s EagerOptimizationStrategy) ShouldRepackObjects(ctx context.Context) (bool, RepackObjectsConfig) {
cfg := RepackObjectsConfig{
- WriteBitmap: len(s.info.Alternates) == 0,
+ WriteBitmap: len(s.info.Alternates.ObjectDirectories) == 0,
WriteMultiPackIndex: true,
}
diff --git a/internal/git/housekeeping/optimization_strategy_test.go b/internal/git/housekeeping/optimization_strategy_test.go
index 8e9526d7d..165f38ff2 100644
--- a/internal/git/housekeeping/optimization_strategy_test.go
+++ b/internal/git/housekeeping/optimization_strategy_test.go
@@ -7,9 +7,9 @@ import (
"time"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
)
@@ -41,7 +41,6 @@ func testHeuristicalOptimizationStrategyShouldRepackObjects(t *testing.T, ctx co
Exists: false,
},
},
- Alternates: []string{},
},
},
expectedNeeded: true,
@@ -64,7 +63,9 @@ func testHeuristicalOptimizationStrategyShouldRepackObjects(t *testing.T, ctx co
Exists: false,
},
},
- Alternates: []string{"something"},
+ Alternates: stats.AlternatesInfo{
+ ObjectDirectories: []string{"something"},
+ },
},
},
// If we have no bitmap in the repository we'd normally want to fully repack
@@ -394,7 +395,9 @@ func testHeuristicalOptimizationStrategyShouldRepackObjects(t *testing.T, ctx co
PackfileCount: 1,
},
},
- Alternates: []string{"object-pool"},
+ Alternates: stats.AlternatesInfo{
+ ObjectDirectories: []string{"object-pool"},
+ },
},
},
expectedNeeded: true,
@@ -417,7 +420,9 @@ func testHeuristicalOptimizationStrategyShouldRepackObjects(t *testing.T, ctx co
PackfileCount: 1,
},
},
- Alternates: []string{"object-pool"},
+ Alternates: stats.AlternatesInfo{
+ ObjectDirectories: []string{"object-pool"},
+ },
},
},
expectedNeeded: true,
@@ -434,6 +439,49 @@ func testHeuristicalOptimizationStrategyShouldRepackObjects(t *testing.T, ctx co
},
),
},
+ {
+ desc: "alternates modified after last full repack",
+ strategy: HeuristicalOptimizationStrategy{
+ info: stats.RepositoryInfo{
+ Packfiles: stats.PackfilesInfo{
+ Count: 1,
+ MultiPackIndex: stats.MultiPackIndexInfo{
+ Exists: true,
+ PackfileCount: 1,
+ },
+ LastFullRepack: time.Now().Add(-1 * time.Hour),
+ },
+ Alternates: stats.AlternatesInfo{
+ LastModified: time.Now(),
+ },
+ },
+ },
+ expectedNeeded: true,
+ expectedConfig: RepackObjectsConfig{
+ Strategy: RepackObjectsStrategyFullWithCruft,
+ WriteBitmap: true,
+ WriteMultiPackIndex: true,
+ },
+ },
+ {
+ desc: "alternates modified before last full repack",
+ strategy: HeuristicalOptimizationStrategy{
+ info: stats.RepositoryInfo{
+ Packfiles: stats.PackfilesInfo{
+ Count: 1,
+ MultiPackIndex: stats.MultiPackIndexInfo{
+ Exists: true,
+ PackfileCount: 1,
+ },
+ LastFullRepack: time.Now(),
+ },
+ Alternates: stats.AlternatesInfo{
+ LastModified: time.Now().Add(-1 * time.Hour),
+ },
+ },
+ },
+ expectedNeeded: false,
+ },
} {
t.Run(tc.desc, func(t *testing.T) {
repackNeeded, repackCfg := tc.strategy.ShouldRepackObjects(ctx)
@@ -529,7 +577,9 @@ func testHeuristicalOptimizationStrategyShouldRepackObjects(t *testing.T, ctx co
Exists: true,
},
},
- Alternates: tc.alternates,
+ Alternates: stats.AlternatesInfo{
+ ObjectDirectories: tc.alternates,
+ },
},
expireBefore: expireBefore,
}
@@ -991,7 +1041,9 @@ func TestEagerOptimizationStrategy(t *testing.T) {
desc: "alternate",
strategy: EagerOptimizationStrategy{
info: stats.RepositoryInfo{
- Alternates: []string{"path/to/alternate"},
+ Alternates: stats.AlternatesInfo{
+ ObjectDirectories: []string{"path/to/alternate"},
+ },
},
expireBefore: expireBefore,
},
@@ -1017,7 +1069,9 @@ func TestEagerOptimizationStrategy(t *testing.T) {
strategy: EagerOptimizationStrategy{
info: stats.RepositoryInfo{
IsObjectPool: true,
- Alternates: []string{"path/to/alternate"},
+ Alternates: stats.AlternatesInfo{
+ ObjectDirectories: []string{"path/to/alternate"},
+ },
},
expireBefore: expireBefore,
},
diff --git a/internal/git/housekeeping/optimize_repository.go b/internal/git/housekeeping/optimize_repository.go
index 728457f4f..ec010d33a 100644
--- a/internal/git/housekeeping/optimize_repository.go
+++ b/internal/git/housekeeping/optimize_repository.go
@@ -158,7 +158,7 @@ func optimizeRepository(
}()
timer := prometheus.NewTimer(m.tasksLatency.WithLabelValues("clean-stale-data"))
- if err := m.CleanStaleData(ctx, repo); err != nil {
+ if err := m.CleanStaleData(ctx, repo, DefaultStaleDataCleanup()); err != nil {
return fmt.Errorf("could not execute houskeeping: %w", err)
}
timer.ObserveDuration()
diff --git a/internal/git/housekeeping/optimize_repository_ext_test.go b/internal/git/housekeeping/optimize_repository_ext_test.go
index 9bb10127d..b27fe0a1a 100644
--- a/internal/git/housekeeping/optimize_repository_ext_test.go
+++ b/internal/git/housekeeping/optimize_repository_ext_test.go
@@ -12,13 +12,13 @@ import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/housekeeping"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/git/housekeeping/optimize_repository_test.go b/internal/git/housekeeping/optimize_repository_test.go
index 21fecabfd..419e039ba 100644
--- a/internal/git/housekeeping/optimize_repository_test.go
+++ b/internal/git/housekeeping/optimize_repository_test.go
@@ -14,8 +14,8 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -24,8 +24,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
gitalycfgprom "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/prometheus"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
)
@@ -460,13 +460,20 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
gitVersion, err := gittest.NewCommandFactory(t, cfg).GitVersion(ctx)
require.NoError(t, err)
- linkRepoToPool := func(t *testing.T, repoPath, poolPath string) {
+ earlierDate := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local)
+ laterDate := time.Date(2022, 12, 1, 12, 0, 0, 0, time.Local)
+
+ linkRepoToPool := func(t *testing.T, repoPath, poolPath string, date time.Time) {
t.Helper()
+
+ alternatesPath := filepath.Join(repoPath, "objects", "info", "alternates")
+
require.NoError(t, os.WriteFile(
- filepath.Join(repoPath, "objects", "info", "alternates"),
+ alternatesPath,
[]byte(filepath.Join(poolPath, "objects")),
perm.PrivateFile,
))
+ require.NoError(t, os.Chtimes(alternatesPath, date, date))
}
readPackfiles := func(t *testing.T, repoPath string) []string {
@@ -823,7 +830,8 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
RelativePath: gittest.NewObjectPoolName(t),
})
- linkRepoToPool(t, repoPath, poolPath)
+ require.NoError(t, stats.UpdateFullRepackTimestamp(repoPath, laterDate))
+ linkRepoToPool(t, repoPath, poolPath, earlierDate)
return setupData{
repo: localrepo.NewTestRepo(t, cfg, repo),
@@ -849,7 +857,10 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
SkipCreationViaService: true,
RelativePath: relativePath,
})
- linkRepoToPool(t, repoPath, poolPath)
+
+ require.NoError(t, stats.UpdateFullRepackTimestamp(repoPath, laterDate))
+ linkRepoToPool(t, repoPath, poolPath, earlierDate)
+
gittest.WriteRef(t, cfg, repoPath, "refs/heads/some-branch", commitID)
return setupData{
@@ -874,7 +885,8 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
SkipCreationViaService: true,
RelativePath: relativePath,
})
- linkRepoToPool(t, repoPath, poolPath)
+ require.NoError(t, stats.UpdateFullRepackTimestamp(repoPath, laterDate))
+ linkRepoToPool(t, repoPath, poolPath, earlierDate)
gittest.WriteCommit(t, cfg, repoPath, gittest.WithParents(commitID), gittest.WithBranch("some-branch"))
return setupData{
@@ -889,6 +901,46 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
},
},
{
+ desc: "recently linked repository gets a full repack",
+ setup: func(t *testing.T, relativePath string) setupData {
+ _, poolPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
+ SkipCreationViaService: true,
+ RelativePath: gittest.NewObjectPoolName(t),
+ })
+
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
+ SkipCreationViaService: true,
+ RelativePath: relativePath,
+ })
+ gittest.WriteCommit(t, cfg, repoPath)
+
+ // Pretend that the last full repack has happened before creating
+ // the gitalternates file. This should cause a full repack in order
+ // to deduplicate all objects.
+ require.NoError(t, stats.UpdateFullRepackTimestamp(repoPath, earlierDate))
+ linkRepoToPool(t, repoPath, poolPath, laterDate)
+
+ return setupData{
+ repo: localrepo.NewTestRepo(t, cfg, repo),
+ expectedMetrics: []metric{
+ {name: "packed_objects_full_with_cruft", status: "success", count: 1},
+ {name: "written_multi_pack_index", status: "success", count: 1},
+ {name: "total", status: "success", count: 1},
+ },
+ expectedMetricsForPool: []metric{
+ {name: func() string {
+ if gitVersion.GeometricRepackingSupportsAlternates() {
+ return geometricOrIncremental(ctx, "packed_objects_full_with_unreachable", "packed_objects_full_with_loose_unreachable")
+ }
+ return "packed_objects_full_with_loose_unreachable"
+ }(), status: "success", count: 1},
+ {name: "written_multi_pack_index", status: "success", count: 1},
+ {name: "total", status: "success", count: 1},
+ },
+ }
+ },
+ },
+ {
desc: "repository with some deduplicated objects and eager strategy",
setup: func(t *testing.T, relativePath string) setupData {
_, poolPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
@@ -901,7 +953,8 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
SkipCreationViaService: true,
RelativePath: relativePath,
})
- linkRepoToPool(t, repoPath, poolPath)
+ require.NoError(t, stats.UpdateFullRepackTimestamp(repoPath, laterDate))
+ linkRepoToPool(t, repoPath, poolPath, earlierDate)
gittest.WriteCommit(t, cfg, repoPath, gittest.WithParents(commitID), gittest.WithBranch("some-branch"))
return setupData{
@@ -956,7 +1009,8 @@ func testOptimizeRepository(t *testing.T, ctx context.Context) {
// past.
require.Equal(t, repoPackfiles, readPackfiles(t, poolPath))
- linkRepoToPool(t, repoPath, poolPath)
+ require.NoError(t, stats.UpdateFullRepackTimestamp(repoPath, laterDate))
+ linkRepoToPool(t, repoPath, poolPath, earlierDate)
return setupData{
repo: localrepo.NewTestRepo(t, cfg, repo),
diff --git a/internal/git/housekeeping/testhelper_test.go b/internal/git/housekeeping/testhelper_test.go
index 330346bd8..5334733b0 100644
--- a/internal/git/housekeeping/testhelper_test.go
+++ b/internal/git/housekeeping/testhelper_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
)
diff --git a/internal/git/localrepo/commit_test.go b/internal/git/localrepo/commit_test.go
index a95e41273..9238ae7a8 100644
--- a/internal/git/localrepo/commit_test.go
+++ b/internal/git/localrepo/commit_test.go
@@ -32,10 +32,10 @@ func TestWriteCommit(t *testing.T) {
require.NoError(t, err)
treeEntryA := TreeEntry{Path: "file", Mode: "100644", OID: blobID}
- treeA, err := repo.WriteTree(ctx, []TreeEntry{treeEntryA})
+ treeA, err := repo.WriteTree(ctx, []*TreeEntry{&treeEntryA})
require.NoError(t, err)
- treeB, err := repo.WriteTree(ctx, []TreeEntry{
+ treeB, err := repo.WriteTree(ctx, []*TreeEntry{
{Path: "file", Mode: "100644", OID: changedBlobID},
})
require.NoError(t, err)
@@ -203,7 +203,7 @@ func TestWriteCommit_validation(t *testing.T) {
blobID, err := repo.WriteBlob(ctx, "", strings.NewReader("foo"))
require.NoError(t, err)
- treeID, err := repo.WriteTree(ctx, []TreeEntry{
+ treeID, err := repo.WriteTree(ctx, []*TreeEntry{
{
OID: blobID,
Mode: "100644",
diff --git a/internal/git/localrepo/config_test.go b/internal/git/localrepo/config_test.go
index 25bf4ef0c..9db4f6c64 100644
--- a/internal/git/localrepo/config_test.go
+++ b/internal/git/localrepo/config_test.go
@@ -8,10 +8,10 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
"gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/git/localrepo/objects.go b/internal/git/localrepo/objects.go
index 7c44bb17c..a7c505d8b 100644
--- a/internal/git/localrepo/objects.go
+++ b/internal/git/localrepo/objects.go
@@ -11,10 +11,10 @@ import (
"time"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
diff --git a/internal/git/localrepo/objects_test.go b/internal/git/localrepo/objects_test.go
index 258adde45..5793732a2 100644
--- a/internal/git/localrepo/objects_test.go
+++ b/internal/git/localrepo/objects_test.go
@@ -13,13 +13,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/git/localrepo/tree.go b/internal/git/localrepo/tree.go
index 3582cadfa..e32014afe 100644
--- a/internal/git/localrepo/tree.go
+++ b/internal/git/localrepo/tree.go
@@ -4,9 +4,12 @@ import (
"bytes"
"context"
"fmt"
+ "sort"
+ "strings"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
)
// ObjectType is an Enum for the type of object of
@@ -37,6 +40,33 @@ func (e Entries) Less(i, j int) bool {
return e[i].Type < e[j].Type
}
+// TreeEntriesByPath allows a slice of *TreeEntry to be sorted by Path
+type TreeEntriesByPath []*TreeEntry
+
+func (b TreeEntriesByPath) Len() int {
+ return len(b)
+}
+
+func (b TreeEntriesByPath) Swap(i, j int) {
+ b[i], b[j] = b[j], b[i]
+}
+
+func (b TreeEntriesByPath) Less(i, j int) bool {
+ iPath, jPath := b[i].Path, b[j].Path
+
+ // git has an edge case for subtrees where they are always appended with
+ // a '/'. See https://github.com/git/git/blob/v2.40.0/read-cache.c#L491
+ if b[i].Type == Tree {
+ iPath += "/"
+ }
+
+ if b[j].Type == Tree {
+ jPath += "/"
+ }
+
+ return iPath < jPath
+}
+
// ToEnum translates a string representation of the object type into an
// ObjectType enum.
func ToEnum(s string) ObjectType {
@@ -52,19 +82,6 @@ func ToEnum(s string) ObjectType {
}
}
-func fromEnum(t ObjectType) string {
- switch t {
- case Tree:
- return "tree"
- case Blob:
- return "blob"
- case Submodule:
- return "commit"
- default:
- return "unknown"
- }
-}
-
// TreeEntry represents an entry of a git tree object.
type TreeEntry struct {
// OID is the object ID the tree entry refers to.
@@ -84,50 +101,46 @@ func (t *TreeEntry) IsBlob() bool {
// WriteTree writes a new tree object to the given path. This function does not verify whether OIDs
// referred to by tree entries actually exist in the repository.
-func (repo *Repo) WriteTree(ctx context.Context, entries []TreeEntry) (git.ObjectID, error) {
+func (repo *Repo) WriteTree(ctx context.Context, entries []*TreeEntry) (git.ObjectID, error) {
var tree bytes.Buffer
+
+ sort.Stable(TreeEntriesByPath(entries))
+
for _, entry := range entries {
- entryType := entry.Type
-
- if entryType == Unknown {
- switch entry.Mode {
- case "100644":
- fallthrough
- case "100755":
- fallthrough
- case "120000":
- entryType = Blob
- case "040000":
- entryType = Tree
- case "160000":
- entryType = Submodule
- }
- }
+ mode := strings.TrimPrefix(entry.Mode, "0")
+ formattedEntry := fmt.Sprintf("%s %s\000", mode, entry.Path)
- oid := entry.OID
+ oidBytes, err := entry.OID.Bytes()
+ if err != nil {
+ return "", err
+ }
- formattedEntry := fmt.Sprintf("%s %s %s\t%s\000", entry.Mode, fromEnum(entryType), oid.String(), entry.Path)
if _, err := tree.WriteString(formattedEntry); err != nil {
return "", err
}
+
+ if _, err := tree.Write(oidBytes); err != nil {
+ return "", err
+ }
}
options := []git.Option{
- git.Flag{Name: "-z"},
- git.Flag{Name: "--missing"},
+ git.ValueFlag{Name: "-t", Value: "tree"},
+ git.Flag{Name: "-w"},
+ git.Flag{Name: "--stdin"},
}
var stdout, stderr bytes.Buffer
if err := repo.ExecAndWait(ctx,
git.Command{
- Name: "mktree",
+ Name: "hash-object",
Flags: options,
},
git.WithStdout(&stdout),
git.WithStderr(&stderr),
git.WithStdin(&tree),
); err != nil {
- return "", err
+ return "", structerr.New("%w", err).WithMetadata("stderr", stderr.String())
}
objectHash, err := repo.ObjectHash(ctx)
diff --git a/internal/git/localrepo/tree_test.go b/internal/git/localrepo/tree_test.go
index c2bb1f897..92dd71575 100644
--- a/internal/git/localrepo/tree_test.go
+++ b/internal/git/localrepo/tree_test.go
@@ -4,11 +4,14 @@ import (
"bytes"
"os"
"path/filepath"
+ "sort"
+ "strings"
"testing"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
)
@@ -17,6 +20,9 @@ func TestWriteTree(t *testing.T) {
cfg := testcfg.Build(t)
ctx := testhelper.Context(t)
+ gitVersion, err := gittest.NewCommandFactory(t, cfg).GitVersion(ctx)
+ require.NoError(t, err)
+
repoProto, repoPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
SkipCreationViaService: true,
})
@@ -28,7 +34,7 @@ func TestWriteTree(t *testing.T) {
blobID, err := repo.WriteBlob(ctx, "file", bytes.NewBufferString("foobar\n"))
require.NoError(t, err)
- treeID, err := repo.WriteTree(ctx, []TreeEntry{
+ treeID, err := repo.WriteTree(ctx, []*TreeEntry{
{
OID: blobID,
Mode: "100644",
@@ -44,13 +50,14 @@ func TestWriteTree(t *testing.T) {
require.NoError(t, os.Remove(nonExistentBlobPath))
for _, tc := range []struct {
- desc string
- entries []TreeEntry
- expectedEntries []TreeEntry
+ desc string
+ entries []*TreeEntry
+ expectedEntries []TreeEntry
+ expectedErrString string
}{
{
desc: "entry with blob OID",
- entries: []TreeEntry{
+ entries: []*TreeEntry{
{
OID: blobID,
Mode: "100644",
@@ -67,7 +74,7 @@ func TestWriteTree(t *testing.T) {
},
{
desc: "entry with tree OID",
- entries: []TreeEntry{
+ entries: []*TreeEntry{
{
OID: treeID,
Mode: "040000",
@@ -84,7 +91,7 @@ func TestWriteTree(t *testing.T) {
},
{
desc: "mixed tree and blob entries",
- entries: []TreeEntry{
+ entries: []*TreeEntry{
{
OID: treeID,
Mode: "040000",
@@ -121,7 +128,7 @@ func TestWriteTree(t *testing.T) {
},
{
desc: "entry with nonexistent object",
- entries: []TreeEntry{
+ entries: []*TreeEntry{
{
OID: nonExistentBlobID,
Mode: "100644",
@@ -136,12 +143,63 @@ func TestWriteTree(t *testing.T) {
},
},
},
+ {
+ desc: "entry with duplicate file",
+ entries: []*TreeEntry{
+ {
+ OID: blobID,
+ Mode: "100644",
+ Path: "file",
+ },
+ {
+ OID: nonExistentBlobID,
+ Mode: "100644",
+ Path: "file",
+ },
+ },
+ expectedErrString: "duplicateEntries: contains duplicate file entries",
+ },
+ {
+ desc: "entry with malformed mode",
+ entries: []*TreeEntry{
+ {
+ OID: blobID,
+ Mode: "1006442",
+ Path: "file",
+ },
+ },
+ expectedErrString: "badFilemode: contains bad file modes",
+ },
+ {
+ desc: "tries to write .git file",
+ entries: []*TreeEntry{
+ {
+ OID: blobID,
+ Mode: "040000",
+ Path: ".git",
+ },
+ },
+ expectedErrString: "hasDotgit: contains '.git'",
+ },
} {
tc := tc
t.Run(tc.desc, func(t *testing.T) {
t.Parallel()
oid, err := repo.WriteTree(ctx, tc.entries)
+ if tc.expectedErrString != "" {
+ if gitVersion.HashObjectFsck() {
+ switch e := err.(type) {
+ case structerr.Error:
+ stderr := e.Metadata()["stderr"].(string)
+ strings.Contains(stderr, tc.expectedErrString)
+ default:
+ strings.Contains(err.Error(), tc.expectedErrString)
+ }
+ }
+ return
+ }
+
require.NoError(t, err)
output := text.ChompBytes(gittest.Exec(t, cfg, "-C", repoPath, "ls-tree", "-r", string(oid)))
@@ -179,3 +237,134 @@ func TestWriteTree(t *testing.T) {
})
}
}
+
+func TestTreeEntryByPath(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ desc string
+ input []*TreeEntry
+ expected []*TreeEntry
+ }{
+ {
+ desc: "all blobs",
+ input: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "abc",
+ },
+ {
+ Type: Blob,
+ Path: "ab",
+ },
+ {
+ Type: Blob,
+ Path: "a",
+ },
+ },
+ expected: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "a",
+ },
+ {
+ Type: Blob,
+ Path: "ab",
+ },
+ {
+ Type: Blob,
+ Path: "abc",
+ },
+ },
+ },
+ {
+ desc: "blobs and trees",
+ input: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "abc",
+ },
+ {
+ Type: Tree,
+ Path: "ab",
+ },
+ {
+ Type: Blob,
+ Path: "a",
+ },
+ },
+ expected: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "a",
+ },
+ {
+ Type: Tree,
+ Path: "ab",
+ },
+ {
+ Type: Blob,
+ Path: "abc",
+ },
+ },
+ },
+ {
+ desc: "trees get sorted with / appended",
+ input: []*TreeEntry{
+ {
+ Type: Tree,
+ Path: "a",
+ },
+ {
+ Type: Blob,
+ Path: "a+",
+ },
+ },
+ expected: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "a+",
+ },
+ {
+ Type: Tree,
+ Path: "a",
+ },
+ },
+ },
+ {
+ desc: "blobs get sorted without / appended",
+ input: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "a",
+ },
+ {
+ Type: Blob,
+ Path: "a+",
+ },
+ },
+ expected: []*TreeEntry{
+ {
+ Type: Blob,
+ Path: "a",
+ },
+ {
+ Type: Blob,
+ Path: "a+",
+ },
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ sort.Stable(TreeEntriesByPath(tc.input))
+
+ require.Equal(
+ t,
+ tc.expected,
+ tc.input,
+ )
+ })
+ }
+}
diff --git a/internal/git/objectpool/create_test.go b/internal/git/objectpool/create_test.go
index d648cd805..7dbc7abff 100644
--- a/internal/git/objectpool/create_test.go
+++ b/internal/git/objectpool/create_test.go
@@ -8,7 +8,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
@@ -16,6 +15,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/git/objectpool/fetch.go b/internal/git/objectpool/fetch.go
index c4f40825c..36823dd38 100644
--- a/internal/git/objectpool/fetch.go
+++ b/internal/git/objectpool/fetch.go
@@ -11,6 +11,7 @@ import (
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
"github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/housekeeping"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/updateref"
@@ -34,7 +35,7 @@ func (o *ObjectPool) FetchFromOrigin(ctx context.Context, origin *localrepo.Repo
return fmt.Errorf("computing origin repo's path: %w", err)
}
- if err := o.housekeepingManager.CleanStaleData(ctx, o.Repo); err != nil {
+ if err := o.housekeepingManager.CleanStaleData(ctx, o.Repo, housekeeping.DefaultStaleDataCleanup()); err != nil {
return fmt.Errorf("cleaning stale data: %w", err)
}
diff --git a/internal/git/objectpool/fetch_test.go b/internal/git/objectpool/fetch_test.go
index 7188e77ab..d5b516d9e 100644
--- a/internal/git/objectpool/fetch_test.go
+++ b/internal/git/objectpool/fetch_test.go
@@ -11,11 +11,11 @@ import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
)
@@ -328,7 +328,7 @@ func testObjectPoolLogStats(t *testing.T, ctx context.Context) {
IsObjectPool: true,
LooseObjects: stats.LooseObjectsInfo{
Count: 2,
- Size: hashDependentSize(142, 158),
+ Size: hashDependentSize(t, 142, 158),
},
References: stats.ReferencesInfo{
LooseReferencesCount: 1,
@@ -352,7 +352,7 @@ func testObjectPoolLogStats(t *testing.T, ctx context.Context) {
IsObjectPool: true,
LooseObjects: stats.LooseObjectsInfo{
Count: 2,
- Size: hashDependentSize(142, 158),
+ Size: hashDependentSize(t, 142, 158),
},
References: stats.ReferencesInfo{
LooseReferencesCount: 1,
diff --git a/internal/git/objectpool/link_test.go b/internal/git/objectpool/link_test.go
index d2096c5fd..751664c96 100644
--- a/internal/git/objectpool/link_test.go
+++ b/internal/git/objectpool/link_test.go
@@ -7,11 +7,11 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
diff --git a/internal/git/objectpool/testhelper_test.go b/internal/git/objectpool/testhelper_test.go
index 6c610ba15..4efcb5923 100644
--- a/internal/git/objectpool/testhelper_test.go
+++ b/internal/git/objectpool/testhelper_test.go
@@ -5,7 +5,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
@@ -13,6 +12,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
@@ -57,9 +57,9 @@ func setupObjectPool(t *testing.T, ctx context.Context) (config.Cfg, *ObjectPool
return cfg, pool, repo
}
-func hashDependentSize(sha1Size, sha256Size uint64) uint64 {
- if gittest.ObjectHashIsSHA256() {
- return sha256Size
- }
- return sha1Size
+func hashDependentSize(tb testing.TB, sha1Size, sha256Size uint64) uint64 {
+ return gittest.ObjectHashDependent(tb, map[string]uint64{
+ "sha1": sha1Size,
+ "sha256": sha256Size,
+ })
}
diff --git a/internal/git/remoterepo/repository_test.go b/internal/git/remoterepo/repository_test.go
index ba4ef4ddd..5911350ec 100644
--- a/internal/git/remoterepo/repository_test.go
+++ b/internal/git/remoterepo/repository_test.go
@@ -14,8 +14,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/remoterepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
)
diff --git a/internal/git/stats/repository_info.go b/internal/git/stats/repository_info.go
index 5b6cbd82a..f52ba41be 100644
--- a/internal/git/stats/repository_info.go
+++ b/internal/git/stats/repository_info.go
@@ -1,6 +1,7 @@
package stats
import (
+ "bufio"
"bytes"
"context"
"encoding/binary"
@@ -15,7 +16,6 @@ import (
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
- "gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
)
const (
@@ -137,9 +137,8 @@ type RepositoryInfo struct {
References ReferencesInfo `json:"references"`
// CommitGraph contains information about the repository's commit-graphs.
CommitGraph CommitGraphInfo `json:"commit_graph"`
- // Alternates is the list of absolute paths of alternate object databases this repository is
- // connected to.
- Alternates []string `json:"alternates"`
+ // Alternates contains information about alternate object directories.
+ Alternates AlternatesInfo `json:"alternates"`
}
// RepositoryInfoForRepository computes the RepositoryInfo for a repository.
@@ -174,7 +173,7 @@ func RepositoryInfoForRepository(repo *localrepo.Repo) (RepositoryInfo, error) {
return RepositoryInfo{}, fmt.Errorf("checking commit-graph info: %w", err)
}
- info.Alternates, err = readAlternates(repo)
+ info.Alternates, err = AlternatesInfoForRepository(repoPath)
if err != nil {
return RepositoryInfo{}, fmt.Errorf("reading alterantes: %w", err)
}
@@ -487,32 +486,70 @@ func hasPrefixAndSuffix(s, prefix, suffix string) bool {
return strings.HasPrefix(s, prefix) && strings.HasSuffix(s, suffix)
}
-func readAlternates(repo *localrepo.Repo) ([]string, error) {
- repoPath, err := repo.Path()
- if err != nil {
- return nil, fmt.Errorf("getting repository path: %w", err)
- }
+// AlternatesInfo contains information about altenrate object directories the repository is linked
+// to.
+type AlternatesInfo struct {
+ // Exists determines whether the `info/alternates` file exists or not.
+ Exists bool `json:"exists"`
+ // Paths contains the list of paths to object directories that the repository is linked to.
+ ObjectDirectories []string `json:"object_directories,omitempty"`
+ // LastModified is the time when the alternates file has last been modified. Has the zero
+ // value when the alternates file doesn't exist.
+ LastModified time.Time `json:"last_modified"`
+}
- contents, err := os.ReadFile(filepath.Join(repoPath, "objects", "info", "alternates"))
+// AlternatesInfoForRepository reads the alternates file and returns information on it. This
+// function does not return an error in case the alternates file doesn't exist. Existence can be
+// checked via the `Exists` field of the returned `AlternatesInfo` structure.
+func AlternatesInfoForRepository(repoPath string) (AlternatesInfo, error) {
+ file, err := os.Open(filepath.Join(repoPath, "objects", "info", "alternates"))
if err != nil {
if errors.Is(err, os.ErrNotExist) {
- return nil, nil
+ return AlternatesInfo{
+ Exists: false,
+ }, nil
}
- return nil, fmt.Errorf("reading alternates: %w", err)
+ return AlternatesInfo{}, err
+ }
+ defer file.Close()
+
+ stat, err := file.Stat()
+ if err != nil {
+ return AlternatesInfo{}, err
}
- relativeAlternatePaths := strings.Split(text.ChompBytes(contents), "\n")
- alternatePaths := make([]string, 0, len(relativeAlternatePaths))
- for _, relativeAlternatePath := range relativeAlternatePaths {
- if filepath.IsAbs(relativeAlternatePath) {
- alternatePaths = append(alternatePaths, relativeAlternatePath)
- } else {
- alternatePaths = append(alternatePaths, filepath.Join(repoPath, "objects", relativeAlternatePath))
+ var alternatePaths []string
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := scanner.Bytes()
+
+ switch {
+ case len(line) == 0:
+ // Empty lines are skipped by Git.
+ continue
+ case bytes.HasPrefix(line, []byte("#")):
+ // Lines starting with a '#' are comments and thus need to be skipped.
+ continue
+ default:
+ path := scanner.Text()
+
+ if filepath.IsAbs(path) {
+ alternatePaths = append(alternatePaths, path)
+ } else {
+ alternatePaths = append(alternatePaths, filepath.Join(repoPath, "objects", path))
+ }
}
}
+ if err := scanner.Err(); err != nil {
+ return AlternatesInfo{}, fmt.Errorf("scanning alternate paths: %w", err)
+ }
- return alternatePaths, nil
+ return AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: alternatePaths,
+ LastModified: stat.ModTime(),
+ }, nil
}
// BitmapInfo contains information about a packfile or multi-pack-index bitmap.
diff --git a/internal/git/stats/repository_info_test.go b/internal/git/stats/repository_info_test.go
index dbfb1360f..a73c660d3 100644
--- a/internal/git/stats/repository_info_test.go
+++ b/internal/git/stats/repository_info_test.go
@@ -122,6 +122,9 @@ func TestLogObjectInfo(t *testing.T) {
targetRepoPath := filepath.Join(storagePath, targetRepoName)
gittest.Exec(t, cfg, "clone", "--bare", "--shared", repoPath1, "--reference", repoPath1, "--reference", repoPath2, targetRepoPath)
+ alternatesStat, err := os.Stat(filepath.Join(targetRepoPath, "objects", "info", "alternates"))
+ require.NoError(t, err)
+
LogRepositoryInfo(ctx, localrepo.NewTestRepo(t, cfg, &gitalypb.Repository{
StorageName: cfg.Storages[0].Name,
RelativePath: targetRepoName,
@@ -135,9 +138,13 @@ func TestLogObjectInfo(t *testing.T) {
References: ReferencesInfo{
PackedReferencesSize: uint64(packedRefsStat.Size()),
},
- Alternates: []string{
- filepath.Join(repoPath1, "/objects"),
- filepath.Join(repoPath2, "/objects"),
+ Alternates: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ filepath.Join(repoPath1, "/objects"),
+ filepath.Join(repoPath2, "/objects"),
+ },
+ LastModified: alternatesStat.ModTime(),
},
}, repoInfo)
})
@@ -159,7 +166,7 @@ func TestLogObjectInfo(t *testing.T) {
require.Equal(t, RepositoryInfo{
LooseObjects: LooseObjectsInfo{
Count: 2,
- Size: hashDependentSize(142, 158),
+ Size: hashDependentSize(t, 142, 158),
},
References: ReferencesInfo{
LooseReferencesCount: 1,
@@ -179,6 +186,8 @@ func TestRepositoryInfoForRepository(t *testing.T) {
})
alternatePath = filepath.Join(alternatePath, "objects")
+ date := time.Date(2005, 4, 7, 15, 13, 13, 0, time.Local)
+
for _, tc := range []struct {
desc string
setup func(t *testing.T, repoPath string)
@@ -213,7 +222,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
expectedInfo: RepositoryInfo{
Packfiles: PackfilesInfo{
Count: 1,
- Size: hashDependentSize(42, 54),
+ Size: hashDependentSize(t, 42, 54),
ReverseIndexCount: 1,
Bitmap: BitmapInfo{
Exists: true,
@@ -242,7 +251,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
},
Packfiles: PackfilesInfo{
Count: 1,
- Size: hashDependentSize(42, 54),
+ Size: hashDependentSize(t, 42, 54),
ReverseIndexCount: 1,
Bitmap: BitmapInfo{
Exists: true,
@@ -271,12 +280,19 @@ func TestRepositoryInfoForRepository(t *testing.T) {
{
desc: "alternates",
setup: func(t *testing.T, repoPath string) {
- infoAlternatesPath := filepath.Join(repoPath, "objects", "info", "alternates")
- require.NoError(t, os.WriteFile(infoAlternatesPath, []byte(alternatePath), perm.PrivateFile))
+ writeFileWithMtime(t,
+ filepath.Join(repoPath, "objects", "info", "alternates"),
+ []byte(alternatePath),
+ date,
+ )
},
expectedInfo: RepositoryInfo{
- Alternates: []string{
- alternatePath,
+ Alternates: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ alternatePath,
+ },
+ LastModified: date,
},
},
},
@@ -292,7 +308,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
expectedInfo: RepositoryInfo{
LooseObjects: LooseObjectsInfo{
Count: 2,
- Size: hashDependentSize(142, 158),
+ Size: hashDependentSize(t, 142, 158),
},
References: ReferencesInfo{
LooseReferencesCount: 1,
@@ -314,7 +330,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
expectedInfo: RepositoryInfo{
LooseObjects: LooseObjectsInfo{
Count: 2,
- Size: hashDependentSize(142, 158),
+ Size: hashDependentSize(t, 142, 158),
},
References: ReferencesInfo{
LooseReferencesCount: 1,
@@ -341,7 +357,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
expectedInfo: RepositoryInfo{
LooseObjects: LooseObjectsInfo{
Count: 2,
- Size: hashDependentSize(142, 158),
+ Size: hashDependentSize(t, 142, 158),
},
References: ReferencesInfo{
LooseReferencesCount: 1,
@@ -357,10 +373,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
desc: "last full repack timestamp",
setup: func(t *testing.T, repoPath string) {
timestampPath := filepath.Join(repoPath, fullRepackTimestampFilename)
- require.NoError(t, os.WriteFile(timestampPath, nil, perm.PrivateFile))
-
- date := time.Date(2005, 4, 7, 15, 13, 13, 0, time.Local)
- require.NoError(t, os.Chtimes(timestampPath, date, date))
+ writeFileWithMtime(t, timestampPath, nil, date)
},
expectedInfo: RepositoryInfo{
Packfiles: PackfilesInfo{
@@ -371,8 +384,11 @@ func TestRepositoryInfoForRepository(t *testing.T) {
{
desc: "all together",
setup: func(t *testing.T, repoPath string) {
- infoAlternatesPath := filepath.Join(repoPath, "objects", "info", "alternates")
- require.NoError(t, os.WriteFile(infoAlternatesPath, []byte(alternatePath), perm.PrivateFile))
+ writeFileWithMtime(t,
+ filepath.Join(repoPath, "objects", "info", "alternates"),
+ []byte(alternatePath),
+ date,
+ )
// We write a single packed blob.
blobID := gittest.WriteBlob(t, cfg, repoPath, []byte("x"))
@@ -397,7 +413,7 @@ func TestRepositoryInfoForRepository(t *testing.T) {
},
Packfiles: PackfilesInfo{
Count: 1,
- Size: hashDependentSize(42, 54),
+ Size: hashDependentSize(t, 42, 54),
ReverseIndexCount: 1,
GarbageCount: 3,
GarbageSize: 3,
@@ -410,8 +426,12 @@ func TestRepositoryInfoForRepository(t *testing.T) {
References: ReferencesInfo{
LooseReferencesCount: 1,
},
- Alternates: []string{
- alternatePath,
+ Alternates: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ alternatePath,
+ },
+ LastModified: date,
},
},
},
@@ -431,6 +451,201 @@ func TestRepositoryInfoForRepository(t *testing.T) {
}
}
+func TestAlternatesInfoForRepository(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ cfg := testcfg.Build(t)
+
+ date := time.Date(2005, 4, 7, 15, 13, 13, 0, time.Local)
+
+ createRepo := func(t *testing.T) (*gitalypb.Repository, string) {
+ return gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
+ SkipCreationViaService: true,
+ })
+ }
+ writeAlternates := func(t *testing.T, repoPath string, alternates []byte) {
+ writeFileWithMtime(t,
+ filepath.Join(repoPath, "objects", "info", "alternates"),
+ alternates,
+ date,
+ )
+ }
+
+ type setupData struct {
+ repoPath string
+ expectedErr error
+ expectedInfo AlternatesInfo
+ }
+
+ for _, tc := range []struct {
+ desc string
+ setup func(t *testing.T) setupData
+ }{
+ {
+ desc: "invalid path",
+ setup: func(t *testing.T) setupData {
+ return setupData{
+ repoPath: "/does/not/exist",
+ expectedInfo: AlternatesInfo{
+ Exists: false,
+ },
+ }
+ },
+ },
+ {
+ desc: "empty repository",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: false,
+ },
+ }
+ },
+ },
+ {
+ desc: "empty alternates file",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, nil)
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ LastModified: date,
+ },
+ }
+ },
+ },
+ {
+ desc: "missing trailing newline",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, []byte("/absolute"))
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ "/absolute",
+ },
+ LastModified: date,
+ },
+ }
+ },
+ },
+ {
+ desc: "absolute path",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, []byte("/absolute\n"))
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ "/absolute",
+ },
+ LastModified: date,
+ },
+ }
+ },
+ },
+ {
+ desc: "relative path",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, []byte("../../../../../@pools/foo/bar\n"))
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ filepath.Join(cfg.Storages[0].Path, "@pools", "foo", "bar"),
+ },
+ LastModified: date,
+ },
+ }
+ },
+ },
+ {
+ desc: "mixed absolute and relative paths",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, []byte("/absolute\n../../../../../@pools/foo/bar\n"))
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ "/absolute",
+ filepath.Join(cfg.Storages[0].Path, "@pools", "foo", "bar"),
+ },
+ LastModified: date,
+ },
+ }
+ },
+ },
+ {
+ desc: "empty lines",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, []byte("/first\n\n/second\n"))
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ "/first",
+ "/second",
+ },
+ LastModified: date,
+ },
+ }
+ },
+ },
+ {
+ desc: "comment",
+ setup: func(t *testing.T) setupData {
+ _, repoPath := createRepo(t)
+ writeAlternates(t, repoPath, []byte("/first\n# comment\n/second\n"))
+
+ return setupData{
+ repoPath: repoPath,
+ expectedInfo: AlternatesInfo{
+ Exists: true,
+ ObjectDirectories: []string{
+ "/first",
+ "/second",
+ },
+ LastModified: date,
+ },
+ }
+ },
+ },
+ } {
+ tc := tc
+
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
+
+ setup := tc.setup(t)
+
+ info, err := AlternatesInfoForRepository(setup.repoPath)
+ require.Equal(t, setup.expectedErr, err)
+ require.Equal(t, setup.expectedInfo, info)
+ })
+ }
+}
+
func TestReferencesInfoForRepository(t *testing.T) {
t.Parallel()
@@ -576,8 +791,7 @@ func TestCountLooseObjects(t *testing.T) {
beforeCutoffDate := cutoffDate.Add(-1 * time.Minute)
for _, objectPath := range objectPaths {
- require.NoError(t, os.WriteFile(objectPath, []byte("1"), perm.SharedFile))
- require.NoError(t, os.Chtimes(objectPath, afterCutoffDate, afterCutoffDate))
+ writeFileWithMtime(t, objectPath, []byte("1"), afterCutoffDate)
}
// Objects are recent, so with the cutoff-date they shouldn't be counted.
@@ -801,7 +1015,7 @@ func TestPackfileInfoForRepository(t *testing.T) {
},
expectedInfo: PackfilesInfo{
Count: 1,
- Size: hashDependentSize(163, 189),
+ Size: hashDependentSize(t, 163, 189),
ReverseIndexCount: 1,
Bitmap: BitmapInfo{
Exists: true,
@@ -818,7 +1032,7 @@ func TestPackfileInfoForRepository(t *testing.T) {
},
expectedInfo: PackfilesInfo{
Count: 1,
- Size: hashDependentSize(163, 189),
+ Size: hashDependentSize(t, 163, 189),
ReverseIndexCount: 1,
MultiPackIndex: MultiPackIndexInfo{
Exists: true,
@@ -835,7 +1049,7 @@ func TestPackfileInfoForRepository(t *testing.T) {
},
expectedInfo: PackfilesInfo{
Count: 1,
- Size: hashDependentSize(163, 189),
+ Size: hashDependentSize(t, 163, 189),
ReverseIndexCount: 1,
MultiPackIndex: MultiPackIndexInfo{
Exists: true,
@@ -861,7 +1075,7 @@ func TestPackfileInfoForRepository(t *testing.T) {
},
expectedInfo: PackfilesInfo{
Count: 2,
- Size: hashDependentSize(315, 367),
+ Size: hashDependentSize(t, 315, 367),
ReverseIndexCount: 1,
GarbageCount: 1,
GarbageSize: 1,
@@ -886,10 +1100,10 @@ func TestPackfileInfoForRepository(t *testing.T) {
},
expectedInfo: PackfilesInfo{
Count: 2,
- Size: hashDependentSize(318, 371),
+ Size: hashDependentSize(t, 318, 371),
ReverseIndexCount: 2,
CruftCount: 1,
- CruftSize: hashDependentSize(156, 183),
+ CruftSize: hashDependentSize(t, 156, 183),
MultiPackIndex: MultiPackIndexInfo{
Exists: true,
Version: 1,
@@ -1480,9 +1694,15 @@ func TestFullRepackTimestamp(t *testing.T) {
})
}
-func hashDependentSize(sha1, sha256 uint64) uint64 {
- if gittest.DefaultObjectHash.Format == "sha1" {
- return sha1
- }
- return sha256
+func hashDependentSize(tb testing.TB, sha1, sha256 uint64) uint64 {
+ return gittest.ObjectHashDependent(tb, map[string]uint64{
+ "sha1": sha1,
+ "sha256": sha256,
+ })
+}
+
+func writeFileWithMtime(tb testing.TB, path string, content []byte, date time.Time) {
+ tb.Helper()
+ require.NoError(tb, os.WriteFile(path, content, perm.PrivateFile))
+ require.NoError(tb, os.Chtimes(path, date, date))
}
diff --git a/internal/git/updateref/update_with_hooks.go b/internal/git/updateref/update_with_hooks.go
index c2e19b86a..8acbb9065 100644
--- a/internal/git/updateref/update_with_hooks.go
+++ b/internal/git/updateref/update_with_hooks.go
@@ -8,6 +8,7 @@ import (
"strings"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -16,7 +17,6 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
diff --git a/internal/git/updateref/update_with_hooks_test.go b/internal/git/updateref/update_with_hooks_test.go
index 88753701d..fe3a577dd 100644
--- a/internal/git/updateref/update_with_hooks_test.go
+++ b/internal/git/updateref/update_with_hooks_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -18,7 +19,6 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
hookservice "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/hook"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
@@ -229,7 +229,7 @@ func TestUpdaterWithHooks_UpdateReference(t *testing.T) {
expectedErr: "reference-transaction failure",
},
{
- desc: "post-receive error is ignored",
+ desc: "post-receive custom hooks error is ignored",
preReceive: func(t *testing.T, ctx context.Context, repo *gitalypb.Repository, pushOptions, env []string, stdin io.Reader, stdout, stderr io.Writer) error {
return nil
},
@@ -242,9 +242,28 @@ func TestUpdaterWithHooks_UpdateReference(t *testing.T) {
postReceive: func(t *testing.T, ctx context.Context, repo *gitalypb.Repository, pushOptions, env []string, stdin io.Reader, stdout, stderr io.Writer) error {
_, err := io.Copy(stderr, strings.NewReader("post-receive failure"))
require.NoError(t, err)
- return errors.New("ignored")
+ return hook.NewCustomHookError(errors.New("ignored"))
+ },
+ expectedRefDeletion: true,
+ },
+ {
+ desc: "post-receive non-custom hooks error returned",
+ preReceive: func(t *testing.T, ctx context.Context, repo *gitalypb.Repository, pushOptions, env []string, stdin io.Reader, stdout, stderr io.Writer) error {
+ return nil
+ },
+ update: func(t *testing.T, ctx context.Context, repo *gitalypb.Repository, ref, oldValue, newValue string, env []string, stdout, stderr io.Writer) error {
+ return nil
+ },
+ referenceTransaction: func(t *testing.T, ctx context.Context, state hook.ReferenceTransactionState, env []string, stdin io.Reader) error {
+ return nil
+ },
+ postReceive: func(t *testing.T, ctx context.Context, repo *gitalypb.Repository, pushOptions, env []string, stdin io.Reader, stdout, stderr io.Writer) error {
+ _, err := io.Copy(stderr, strings.NewReader("post-receive failure"))
+ require.NoError(t, err)
+ return errors.New("uh oh")
},
expectedRefDeletion: true,
+ expectedErr: "running post-receive hooks: uh oh",
},
}
diff --git a/internal/git/version.go b/internal/git/version.go
index 5048007fa..43cff0475 100644
--- a/internal/git/version.go
+++ b/internal/git/version.go
@@ -75,6 +75,14 @@ func (v Version) IsSupported() bool {
return !v.LessThan(minimumVersion)
}
+// HashObjectFsck detects whether or not the given Git version will do fsck
+// checks when git-hash-object writes objects.
+func (v Version) HashObjectFsck() bool {
+ return !v.LessThan(Version{
+ major: 2, minor: 40, patch: 0,
+ })
+}
+
// PatchIDRespectsBinaries detects whether the given Git version correctly handles binary diffs when
// computing a patch ID. Previous to Git v2.39.0, git-patch-id(1) just completely ignored any binary
// diffs and thus would consider two diffs the same even if a binary changed.
diff --git a/internal/git2go/executor.go b/internal/git2go/executor.go
index dea316d95..5ea382faf 100644
--- a/internal/git2go/executor.go
+++ b/internal/git2go/executor.go
@@ -10,13 +10,13 @@ import (
"strings"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/alternates"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
glog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/labkit/correlation"
)
diff --git a/internal/git2go/featureflags_test.go b/internal/git2go/featureflags_test.go
index 9e71539e1..f5c2b7b8f 100644
--- a/internal/git2go/featureflags_test.go
+++ b/internal/git2go/featureflags_test.go
@@ -8,11 +8,11 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
)
diff --git a/internal/gitaly/client/dial.go b/internal/gitaly/client/dial.go
index def5b5fad..c22bf74e3 100644
--- a/internal/gitaly/client/dial.go
+++ b/internal/gitaly/client/dial.go
@@ -8,7 +8,7 @@ import (
"net/url"
"time"
- "gitlab.com/gitlab-org/gitaly/v16/internal/dnsresolver"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/dnsresolver"
gitalyx509 "gitlab.com/gitlab-org/gitaly/v16/internal/x509"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc"
diff --git a/internal/gitaly/client/dial_test.go b/internal/gitaly/client/dial_test.go
index 3bc1385b7..93119ccfd 100644
--- a/internal/gitaly/client/dial_test.go
+++ b/internal/gitaly/client/dial_test.go
@@ -6,8 +6,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc"
diff --git a/internal/gitaly/config/sentry/sentry.go b/internal/gitaly/config/sentry/sentry.go
index e0acc7f9e..a63207201 100644
--- a/internal/gitaly/config/sentry/sentry.go
+++ b/internal/gitaly/config/sentry/sentry.go
@@ -5,7 +5,7 @@ import (
sentry "github.com/getsentry/sentry-go"
log "github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/panichandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/panichandler"
)
// Config contains configuration for sentry
diff --git a/internal/gitaly/hook/custom.go b/internal/gitaly/hook/custom.go
index d63fc076e..6ccf968a0 100644
--- a/internal/gitaly/hook/custom.go
+++ b/internal/gitaly/hook/custom.go
@@ -20,7 +20,22 @@ import (
type customHooksExecutor func(ctx context.Context, args, env []string, stdin io.Reader, stdout, stderr io.Writer) error
// CustomHookError is returned in case custom hooks return an error.
-type CustomHookError error
+type CustomHookError struct {
+ err error
+}
+
+// NewCustomHookError creates a new CustomHookError.
+func NewCustomHookError(e error) CustomHookError {
+ return CustomHookError{err: e}
+}
+
+func (e CustomHookError) Error() string {
+ return e.err.Error()
+}
+
+func (e CustomHookError) Unwrap() error {
+ return e.err
+}
// newCustomHooksExecutor creates a new hooks executor for custom hooks. Hooks
// are looked up and executed in the following order:
@@ -84,7 +99,7 @@ func (m *GitLabHookManager) newCustomHooksExecutor(repo *gitalypb.Repository, ho
// not be modified, but instead used as-is as the hooks' error
// message given that they may contain output that should be shown
// to the user.
- return CustomHookError(fmt.Errorf("error executing %q: %w", hookFile, err))
+ return NewCustomHookError(fmt.Errorf("error executing %q: %w", hookFile, err))
}
}
diff --git a/internal/gitaly/hook/postreceive_test.go b/internal/gitaly/hook/postreceive_test.go
index 08b12655a..468aa76b9 100644
--- a/internal/gitaly/hook/postreceive_test.go
+++ b/internal/gitaly/hook/postreceive_test.go
@@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -18,7 +18,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
diff --git a/internal/gitaly/hook/prereceive_test.go b/internal/gitaly/hook/prereceive_test.go
index 9362b0ae3..fe2d3c77e 100644
--- a/internal/gitaly/hook/prereceive_test.go
+++ b/internal/gitaly/hook/prereceive_test.go
@@ -9,7 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -17,7 +17,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/hook/sidechannel.go b/internal/gitaly/hook/sidechannel.go
index cc3d52621..224ed40d7 100644
--- a/internal/gitaly/hook/sidechannel.go
+++ b/internal/gitaly/hook/sidechannel.go
@@ -12,8 +12,8 @@ import (
"time"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ gitaly_metadata "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- gitaly_metadata "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"google.golang.org/grpc/metadata"
)
diff --git a/internal/gitaly/hook/sidechannel_test.go b/internal/gitaly/hook/sidechannel_test.go
index de4e0523a..da66709e9 100644
--- a/internal/gitaly/hook/sidechannel_test.go
+++ b/internal/gitaly/hook/sidechannel_test.go
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
grpc_metadata "google.golang.org/grpc/metadata"
)
diff --git a/internal/gitaly/hook/transactions_test.go b/internal/gitaly/hook/transactions_test.go
index da2e6d1d8..bf708b15e 100644
--- a/internal/gitaly/hook/transactions_test.go
+++ b/internal/gitaly/hook/transactions_test.go
@@ -9,12 +9,12 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
diff --git a/internal/gitaly/hook/update_test.go b/internal/gitaly/hook/update_test.go
index 55d8acc06..ab4b6010b 100644
--- a/internal/gitaly/hook/update_test.go
+++ b/internal/gitaly/hook/update_test.go
@@ -7,7 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -15,7 +15,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
diff --git a/internal/gitaly/maintenance/optimize_test.go b/internal/gitaly/maintenance/optimize_test.go
index 7f1d00ff3..cdb48f727 100644
--- a/internal/gitaly/maintenance/optimize_test.go
+++ b/internal/gitaly/maintenance/optimize_test.go
@@ -6,7 +6,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/housekeeping"
@@ -14,6 +13,7 @@ import (
repo "gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/repoutil/create.go b/internal/gitaly/repoutil/create.go
index f4396697c..07dedc61a 100644
--- a/internal/gitaly/repoutil/create.go
+++ b/internal/gitaly/repoutil/create.go
@@ -11,6 +11,7 @@ import (
"time"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
@@ -65,7 +66,7 @@ func Create(
locator storage.Locator,
gitCmdFactory git.CommandFactory,
txManager transaction.Manager,
- repository *gitalypb.Repository,
+ repository repository.GitRepo,
seedRepository func(repository *gitalypb.Repository) error,
options ...CreateOption,
) error {
diff --git a/internal/gitaly/repoutil/lock.go b/internal/gitaly/repoutil/lock.go
index c11fc73fd..a3235ce18 100644
--- a/internal/gitaly/repoutil/lock.go
+++ b/internal/gitaly/repoutil/lock.go
@@ -6,11 +6,11 @@ import (
"path/filepath"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
- "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
// Lock attempts to lock the entire repository directory such that only one
@@ -20,7 +20,7 @@ import (
//
// Returns the error safe.ErrFileAlreadyLocked if the repository is already
// locked.
-func Lock(ctx context.Context, locator storage.Locator, repository *gitalypb.Repository) (func(), error) {
+func Lock(ctx context.Context, locator storage.Locator, repository repository.GitRepo) (func(), error) {
path, err := locator.GetPath(repository)
if err != nil {
return nil, err
diff --git a/internal/gitaly/repoutil/remove.go b/internal/gitaly/repoutil/remove.go
new file mode 100644
index 000000000..817876504
--- /dev/null
+++ b/internal/gitaly/repoutil/remove.go
@@ -0,0 +1,119 @@
+package repoutil
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/repository"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/safe"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/transaction/voting"
+)
+
+// Remove will remove a repository in a race-free way with proper transactional semantics.
+func Remove(
+ ctx context.Context,
+ locator storage.Locator,
+ txManager transaction.Manager,
+ repository repository.GitRepo,
+) error {
+ path, err := locator.GetPath(repository)
+ if err != nil {
+ return structerr.NewInternal("%w", err)
+ }
+
+ tempDir, err := locator.TempDir(repository.GetStorageName())
+ if err != nil {
+ return structerr.NewInternal("temporary directory: %w", err)
+ }
+
+ if err := os.MkdirAll(tempDir, perm.SharedDir); err != nil {
+ return structerr.NewInternal("%w", err)
+ }
+
+ base := filepath.Base(path)
+ destDir := filepath.Join(tempDir, base+"+removed")
+
+ // Check whether the repository exists. If not, then there is nothing we can
+ // remove. Historically, we didn't return an error in this case, which was just
+ // plain bad RPC design: callers should be able to act on this, and if they don't
+ // care they may still just return `NotFound` errors.
+ if _, err := os.Stat(path); err != nil {
+ if os.IsNotExist(err) {
+ return structerr.NewNotFound("repository does not exist")
+ }
+
+ return structerr.NewInternal("statting repository: %w", err)
+ }
+
+ // Lock the repository such that it cannot be created or removed by any concurrent
+ // RPC call.
+ unlock, err := Lock(ctx, locator, repository)
+ if err != nil {
+ if errors.Is(err, safe.ErrFileAlreadyLocked) {
+ return structerr.NewFailedPrecondition("repository is already locked")
+ }
+ return structerr.NewInternal("locking repository for removal: %w", err)
+ }
+ defer unlock()
+
+ // Recheck whether the repository still exists after we have taken the lock. It
+ // could be a concurrent RPC call removed the repository while we have not yet been
+ // holding the lock.
+ if _, err := os.Stat(path); err != nil {
+ if os.IsNotExist(err) {
+ return structerr.NewNotFound("repository was concurrently removed")
+ }
+ return structerr.NewInternal("re-statting repository: %w", err)
+ }
+
+ if err := voteOnAction(ctx, txManager, repository, voting.Prepared); err != nil {
+ return structerr.NewInternal("vote on rename: %w", err)
+ }
+
+ // We move the repository into our temporary directory first before we start to
+ // delete it. This is done such that we don't leave behind a partially-removed and
+ // thus likely corrupt repository.
+ if err := os.Rename(path, destDir); err != nil {
+ return structerr.NewInternal("staging repository for removal: %w", err)
+ }
+
+ if err := os.RemoveAll(destDir); err != nil {
+ return structerr.NewInternal("removing repository: %w", err)
+ }
+
+ if err := voteOnAction(ctx, txManager, repository, voting.Committed); err != nil {
+ return structerr.NewInternal("vote on finalizing: %w", err)
+ }
+
+ return nil
+}
+
+func voteOnAction(
+ ctx context.Context,
+ txManager transaction.Manager,
+ repo repository.GitRepo,
+ phase voting.Phase,
+) error {
+ return transaction.RunOnContext(ctx, func(tx txinfo.Transaction) error {
+ var voteStep string
+ switch phase {
+ case voting.Prepared:
+ voteStep = "pre-remove"
+ case voting.Committed:
+ voteStep = "post-remove"
+ default:
+ return fmt.Errorf("invalid removal step: %d", phase)
+ }
+
+ vote := fmt.Sprintf("%s %s", voteStep, repo.GetRelativePath())
+ return txManager.Vote(ctx, tx, voting.VoteFromData([]byte(vote)), phase)
+ })
+}
diff --git a/internal/gitaly/repoutil/remove_test.go b/internal/gitaly/repoutil/remove_test.go
new file mode 100644
index 000000000..0cbc158f1
--- /dev/null
+++ b/internal/gitaly/repoutil/remove_test.go
@@ -0,0 +1,92 @@
+package repoutil
+
+import (
+ "context"
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+)
+
+func TestRemove(t *testing.T) {
+ t.Parallel()
+
+ for _, tc := range []struct {
+ desc string
+ createRepo func(tb testing.TB, ctx context.Context, cfg config.Cfg) (*gitalypb.Repository, string)
+ expectedErr error
+ }{
+ {
+ desc: "success",
+ createRepo: func(tb testing.TB, ctx context.Context, cfg config.Cfg) (*gitalypb.Repository, string) {
+ return gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
+ SkipCreationViaService: true,
+ })
+ },
+ },
+ {
+ desc: "does not exist",
+ createRepo: func(tb testing.TB, ctx context.Context, cfg config.Cfg) (*gitalypb.Repository, string) {
+ repo := &gitalypb.Repository{StorageName: cfg.Storages[0].Name, RelativePath: "/does/not/exist"}
+ return repo, ""
+ },
+ expectedErr: structerr.NewNotFound("repository does not exist"),
+ },
+ {
+ desc: "locked",
+ createRepo: func(tb testing.TB, ctx context.Context, cfg config.Cfg) (*gitalypb.Repository, string) {
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
+ SkipCreationViaService: true,
+ })
+
+ // Simulate a concurrent RPC holding the repository lock.
+ lockPath := repoPath + ".lock"
+ require.NoError(t, os.WriteFile(lockPath, []byte{}, perm.SharedFile))
+ tb.Cleanup(func() {
+ require.NoError(t, os.RemoveAll(lockPath))
+ })
+
+ return repo, repoPath
+ },
+ expectedErr: structerr.NewFailedPrecondition("repository is already locked"),
+ },
+ } {
+ tc := tc
+
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ cfg := testcfg.Build(t)
+ locator := config.NewLocator(cfg)
+ txManager := transaction.NewTrackingManager()
+
+ repo, repoPath := tc.createRepo(t, ctx, cfg)
+
+ if repoPath != "" {
+ require.DirExists(t, repoPath)
+ }
+
+ err := Remove(ctx, locator, txManager, repo)
+
+ if tc.expectedErr != nil {
+ require.Equal(t, tc.expectedErr, err)
+ return
+ }
+
+ require.NoError(t, err)
+
+ if repoPath != "" {
+ require.NoDirExists(t, repoPath)
+ }
+ })
+ }
+}
diff --git a/internal/gitaly/server/auth_test.go b/internal/gitaly/server/auth_test.go
index 566b5f93b..2e83b9a34 100644
--- a/internal/gitaly/server/auth_test.go
+++ b/internal/gitaly/server/auth_test.go
@@ -1,5 +1,3 @@
-//go:build !gitaly_test_sha256
-
package server
import (
@@ -16,7 +14,6 @@ import (
"github.com/stretchr/testify/require"
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
@@ -28,7 +25,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
@@ -318,8 +316,8 @@ func TestAuthBeforeLimit(t *testing.T) {
repo, repoPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
SkipCreationViaService: true,
- Seed: gittest.SeedGitLabTest,
})
+ commitID := gittest.WriteCommit(t, cfg, repoPath)
gitlabURL, cleanup := gitlab.SetupAndStartGitlabServer(t, cfg.GitlabShell.Dir, &gitlab.TestServerOptions{
SecretToken: "secretToken",
@@ -352,7 +350,7 @@ sleep %v
_, err := client.UserCreateTag(ctx, &gitalypb.UserCreateTagRequest{
Repository: repo,
TagName: []byte(fmt.Sprintf("tag-name-%d", i)),
- TargetRevision: []byte("c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd"),
+ TargetRevision: []byte(commitID),
User: gittest.TestUser,
Message: []byte("a new tag!"),
})
diff --git a/internal/gitaly/server/server.go b/internal/gitaly/server/server.go
index 89668d1f2..6bdf6a734 100644
--- a/internal/gitaly/server/server.go
+++ b/internal/gitaly/server/server.go
@@ -8,22 +8,22 @@ import (
grpcmwlogrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
grpcmwtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/server/auth"
- "gitlab.com/gitlab-org/gitaly/v16/internal/grpcstats"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/grpcstats"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/cache"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/commandstatshandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/panichandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/sentryhandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/statushandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/fieldextractors"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
gitalylog "gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/internal/logsanitizer"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/cache"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/commandstatshandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/featureflag"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/panichandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/sentryhandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/statushandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc"
diff --git a/internal/gitaly/server/server_factory.go b/internal/gitaly/server/server_factory.go
index 847e5387d..10afb3ce3 100644
--- a/internal/gitaly/server/server_factory.go
+++ b/internal/gitaly/server/server_factory.go
@@ -4,10 +4,10 @@ import (
"sync"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"google.golang.org/grpc"
)
diff --git a/internal/gitaly/server/server_factory_test.go b/internal/gitaly/server/server_factory_test.go
index c61b374eb..4c54bd720 100644
--- a/internal/gitaly/server/server_factory_test.go
+++ b/internal/gitaly/server/server_factory_test.go
@@ -16,10 +16,10 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/bootstrap/starter"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"golang.org/x/sync/errgroup"
diff --git a/internal/gitaly/service/dependencies.go b/internal/gitaly/service/dependencies.go
index 90044ff9c..3eb528e75 100644
--- a/internal/gitaly/service/dependencies.go
+++ b/internal/gitaly/service/dependencies.go
@@ -2,7 +2,6 @@ package service
import (
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
@@ -14,7 +13,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/streamcache"
)
diff --git a/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-after.txt b/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-after.txt
index ef577df80..f3584af8e 100644
--- a/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-after.txt
+++ b/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-after.txt
@@ -15,7 +15,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v15/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/transaction"
- "gitlab.com/gitlab-org/gitaly/v15/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v15/internal/safe"
"gitlab.com/gitlab-org/gitaly/v15/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v15/internal/tempdir"
diff --git a/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-before.txt b/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-before.txt
index b221a32e5..8f7604a59 100644
--- a/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-before.txt
+++ b/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-before.txt
@@ -14,7 +14,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v15/internal/command"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/transaction"
- "gitlab.com/gitlab-org/gitaly/v15/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v15/internal/safe"
"gitlab.com/gitlab-org/gitaly/v15/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v15/internal/transaction/txinfo"
diff --git a/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-diff.txt b/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-diff.txt
index cea355b74..bc99ce839 100644
--- a/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-diff.txt
+++ b/internal/gitaly/service/diff/testdata/file-with-multiple-chunks-diff.txt
@@ -5,7 +5,7 @@
+ "gitlab.com/gitlab-org/gitaly/v15/internal/git/repository"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/transaction"
- "gitlab.com/gitlab-org/gitaly/v15/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v15/internal/safe"
"gitlab.com/gitlab-org/gitaly/v15/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/tempdir"
diff --git a/internal/gitaly/service/hook/pack_objects.go b/internal/gitaly/service/hook/pack_objects.go
index c5a904bd7..2ee394c39 100644
--- a/internal/gitaly/service/hook/pack_objects.go
+++ b/internal/gitaly/service/hook/pack_objects.go
@@ -18,12 +18,12 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/pktline"
gitalyhook "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/stream"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/gitaly/service/hook/pack_objects_test.go b/internal/gitaly/service/hook/pack_objects_test.go
index 4c2de55ab..3a606fe5e 100644
--- a/internal/gitaly/service/hook/pack_objects_test.go
+++ b/internal/gitaly/service/hook/pack_objects_test.go
@@ -18,14 +18,14 @@ import (
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/pktline"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
hookPkg "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/streamcache"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/hook/post_receive_test.go b/internal/gitaly/service/hook/post_receive_test.go
index 0551df0ff..651798908 100644
--- a/internal/gitaly/service/hook/post_receive_test.go
+++ b/internal/gitaly/service/hook/post_receive_test.go
@@ -10,13 +10,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/prometheus"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/hook/pre_receive_test.go b/internal/gitaly/service/hook/pre_receive_test.go
index caa76df4e..15223a0ca 100644
--- a/internal/gitaly/service/hook/pre_receive_test.go
+++ b/internal/gitaly/service/hook/pre_receive_test.go
@@ -13,13 +13,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/prometheus"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/hook/reference_transaction_test.go b/internal/gitaly/service/hook/reference_transaction_test.go
index 793de70e9..ec722b3b0 100644
--- a/internal/gitaly/service/hook/reference_transaction_test.go
+++ b/internal/gitaly/service/hook/reference_transaction_test.go
@@ -9,10 +9,10 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/hook/server.go b/internal/gitaly/service/hook/server.go
index b1c1ed283..55de7f68e 100644
--- a/internal/gitaly/service/hook/server.go
+++ b/internal/gitaly/service/hook/server.go
@@ -6,7 +6,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
gitalyhook "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/streamcache"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
diff --git a/internal/gitaly/service/hook/update_test.go b/internal/gitaly/service/hook/update_test.go
index 775f864f6..257e05c6e 100644
--- a/internal/gitaly/service/hook/update_test.go
+++ b/internal/gitaly/service/hook/update_test.go
@@ -11,10 +11,10 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/gitaly/service/internalgitaly/backup_repos.go b/internal/gitaly/service/internalgitaly/backup_repos.go
new file mode 100644
index 000000000..ff43b5b5e
--- /dev/null
+++ b/internal/gitaly/service/internalgitaly/backup_repos.go
@@ -0,0 +1,87 @@
+package internalgitaly
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/backup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+)
+
+func (s server) BackupRepos(stream gitalypb.InternalGitaly_BackupReposServer) error {
+ ctx := stream.Context()
+
+ request, err := stream.Recv()
+ if err != nil {
+ return fmt.Errorf("backup repos: first request: %w", err)
+ }
+
+ if err := validateBackupReposRequest(request); err != nil {
+ return structerr.NewInvalidArgument("backup repos: first request: %w", err)
+ }
+
+ header := request.GetHeader()
+ backupID := header.GetBackupId()
+
+ sink, err := backup.ResolveSink(ctx, header.GetStorageUrl())
+ if err != nil {
+ return structerr.NewInvalidArgument("backup repos: resolve sink: %w", err)
+ }
+
+ locator, err := backup.ResolveLocator("pointer", sink)
+ if err != nil {
+ return structerr.NewInvalidArgument("backup repos: resolve locator: %w", err)
+ }
+
+ manager := backup.NewManagerLocal(sink, locator, s.locator, s.gitCmdFactory, s.catfileCache, backupID)
+ pipeline := backup.NewLoggingPipeline(ctxlogrus.Extract(ctx))
+
+ for {
+ for _, repo := range request.GetRepositories() {
+ pipeline.Handle(ctx, backup.NewCreateCommand(
+ manager,
+ // ServerInfo will be removed once restore methods are added to
+ // backup.Repository. Even though it is unused it must be
+ // non-zero so that storage.ExtractGitalyServer is not called.
+ storage.ServerInfo{Address: "unused"},
+ repo,
+ false,
+ ))
+ }
+
+ var err error
+ request, err = stream.Recv()
+ if errors.Is(err, io.EOF) {
+ break
+ } else if err != nil {
+ return fmt.Errorf("backup repos: receive: %w", err)
+ }
+ }
+
+ if err := pipeline.Done(); err != nil {
+ return fmt.Errorf("backup repos: %w", err)
+ }
+
+ if err := stream.SendAndClose(&gitalypb.BackupReposResponse{}); err != nil {
+ return fmt.Errorf("backup repos: %w", err)
+ }
+
+ return nil
+}
+
+func validateBackupReposRequest(req *gitalypb.BackupReposRequest) error {
+ header := req.Header
+ switch {
+ case header == nil:
+ return fmt.Errorf("empty Header")
+ case header.GetBackupId() == "":
+ return fmt.Errorf("empty BackupId")
+ case header.GetStorageUrl() == "":
+ return fmt.Errorf("empty StorageUrl")
+ }
+ return nil
+}
diff --git a/internal/gitaly/service/internalgitaly/backup_repos_test.go b/internal/gitaly/service/internalgitaly/backup_repos_test.go
new file mode 100644
index 000000000..6b00d4da0
--- /dev/null
+++ b/internal/gitaly/service/internalgitaly/backup_repos_test.go
@@ -0,0 +1,161 @@
+package internalgitaly
+
+import (
+ "context"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/backup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+func TestServerBackupRepos(t *testing.T) {
+ t.Parallel()
+
+ const backupID = "abc123"
+
+ type setupData struct {
+ requests []*gitalypb.BackupReposRequest
+ expectedRepos []*gitalypb.Repository
+ }
+
+ for _, tc := range []struct {
+ desc string
+ setup func(tb testing.TB, ctx context.Context, cfg config.Cfg, storageURL string) setupData
+ expectedErr error
+ }{
+ {
+ desc: "missing header",
+ setup: func(tb testing.TB, ctx context.Context, cfg config.Cfg, storageURL string) setupData {
+ return setupData{requests: []*gitalypb.BackupReposRequest{{}}}
+ },
+ expectedErr: status.Error(codes.InvalidArgument, `backup repos: first request: empty Header`),
+ },
+ {
+ desc: "missing backup ID",
+ setup: func(tb testing.TB, ctx context.Context, cfg config.Cfg, storageURL string) setupData {
+ return setupData{
+ requests: []*gitalypb.BackupReposRequest{{Header: &gitalypb.BackupReposRequest_Header{}}},
+ }
+ },
+ expectedErr: status.Error(codes.InvalidArgument, `backup repos: first request: empty BackupId`),
+ },
+ {
+ desc: "missing storage URL",
+ setup: func(tb testing.TB, ctx context.Context, cfg config.Cfg, storageURL string) setupData {
+ return setupData{
+ requests: []*gitalypb.BackupReposRequest{{Header: &gitalypb.BackupReposRequest_Header{
+ BackupId: backupID,
+ }}},
+ }
+ },
+ expectedErr: status.Error(codes.InvalidArgument, `backup repos: first request: empty StorageUrl`),
+ },
+ {
+ desc: "invalid storage URL",
+ setup: func(tb testing.TB, ctx context.Context, cfg config.Cfg, storageURL string) setupData {
+ return setupData{
+ requests: []*gitalypb.BackupReposRequest{
+ {
+ Header: &gitalypb.BackupReposRequest_Header{
+ BackupId: backupID,
+ StorageUrl: "%invalid%",
+ },
+ },
+ },
+ }
+ },
+ expectedErr: status.Error(codes.InvalidArgument, `backup repos: resolve sink: parse "%invalid%": invalid URL escape "%in"`),
+ },
+ {
+ desc: "success",
+ setup: func(tb testing.TB, ctx context.Context, cfg config.Cfg, storageURL string) setupData {
+ var repos []*gitalypb.Repository
+ for i := 0; i < 5; i++ {
+ repo, repoPath := gittest.CreateRepository(tb, ctx, cfg, gittest.CreateRepositoryConfig{
+ SkipCreationViaService: true,
+ })
+ gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch(git.DefaultBranch))
+ repos = append(repos, repo)
+ }
+
+ return setupData{
+ requests: []*gitalypb.BackupReposRequest{
+ {
+ Header: &gitalypb.BackupReposRequest_Header{
+ BackupId: backupID,
+ StorageUrl: storageURL,
+ },
+ Repositories: repos[:len(repos)/2],
+ },
+ {
+ Repositories: repos[len(repos)/2:],
+ },
+ },
+ expectedRepos: repos,
+ }
+ },
+ },
+ } {
+ tc := tc
+
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ cfg := testcfg.Build(t)
+ storageURL := testhelper.TempDir(t)
+ setupData := tc.setup(t, ctx, cfg, storageURL)
+
+ catfileCache := catfile.NewCache(cfg)
+ t.Cleanup(catfileCache.Stop)
+
+ srv := NewServer(
+ cfg.Storages,
+ config.NewLocator(cfg),
+ gittest.NewCommandFactory(t, cfg),
+ catfileCache,
+ )
+
+ client := setupInternalGitalyService(t, cfg, srv)
+
+ stream, err := client.BackupRepos(ctx)
+ require.NoError(t, err)
+
+ for _, req := range setupData.requests {
+ err = stream.Send(req)
+ require.NoError(t, err)
+ }
+
+ _, err = stream.CloseAndRecv()
+ if tc.expectedErr == nil {
+ require.NoError(t, err)
+ } else {
+ require.Equal(t, tc.expectedErr, err)
+ }
+
+ t.Log(storageURL)
+ sink, err := backup.ResolveSink(ctx, storageURL)
+ require.NoError(t, err)
+
+ for _, repo := range setupData.expectedRepos {
+ relativePath := strings.TrimSuffix(repo.GetRelativePath(), ".git")
+ bundlePath := filepath.Join(relativePath, backupID, "001.bundle")
+
+ r, err := sink.GetReader(ctx, bundlePath)
+ require.NoError(t, err)
+ testhelper.MustClose(t, r)
+ }
+ })
+ }
+}
diff --git a/internal/gitaly/service/internalgitaly/server.go b/internal/gitaly/service/internalgitaly/server.go
index b24ea4ede..d0ce88352 100644
--- a/internal/gitaly/service/internalgitaly/server.go
+++ b/internal/gitaly/service/internalgitaly/server.go
@@ -1,16 +1,32 @@
package internalgitaly
import (
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
type server struct {
gitalypb.UnimplementedInternalGitalyServer
- storages []config.Storage
+ storages []config.Storage
+ locator storage.Locator
+ gitCmdFactory git.CommandFactory
+ catfileCache catfile.Cache
}
// NewServer return an instance of the Gitaly service.
-func NewServer(storages []config.Storage) gitalypb.InternalGitalyServer {
- return &server{storages: storages}
+func NewServer(
+ storages []config.Storage,
+ locator storage.Locator,
+ gitCmdFactory git.CommandFactory,
+ catfileCache catfile.Cache,
+) gitalypb.InternalGitalyServer {
+ return &server{
+ storages: storages,
+ locator: locator,
+ gitCmdFactory: gitCmdFactory,
+ catfileCache: catfileCache,
+ }
}
diff --git a/internal/gitaly/service/internalgitaly/walkrepos_test.go b/internal/gitaly/service/internalgitaly/walkrepos_test.go
index b69a8cf70..de4e5b23d 100644
--- a/internal/gitaly/service/internalgitaly/walkrepos_test.go
+++ b/internal/gitaly/service/internalgitaly/walkrepos_test.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
@@ -70,12 +71,20 @@ func TestWalkRepos(t *testing.T) {
os.Chtimes(testRepo2Path, time.Now(), modifiedDate),
)
+ catfileCache := catfile.NewCache(cfg)
+ t.Cleanup(catfileCache.Stop)
+
// to test a directory being deleted during a walk, we must delete a directory after
// the file walk has started. To achieve that, we wrap the server to pass down a wrapped
// stream that allows us to hook in to stream responses. We then delete 'b' when
// the first repo 'a' is being streamed to the client.
deleteOnce := sync.Once{}
- srv := NewServer([]config.Storage{{Name: storageName, Path: storageRoot}})
+ srv := NewServer(
+ []config.Storage{{Name: storageName, Path: storageRoot}},
+ config.NewLocator(cfg),
+ gittest.NewCommandFactory(t, cfg),
+ catfileCache,
+ )
wsrv := &serverWrapper{
srv,
func(r *gitalypb.WalkReposRequest, s gitalypb.InternalGitaly_WalkReposServer) error {
diff --git a/internal/gitaly/service/objectpool/alternates.go b/internal/gitaly/service/objectpool/alternates.go
index 89486b990..db8e4f578 100644
--- a/internal/gitaly/service/objectpool/alternates.go
+++ b/internal/gitaly/service/objectpool/alternates.go
@@ -10,13 +10,11 @@ import (
"time"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/command"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
@@ -204,35 +202,17 @@ func (s *server) removeAlternatesIfOk(ctx context.Context, repo *localrepo.Repo,
}
}()
- var err error
- var cmd *command.Command
-
- if featureflag.RevlistForConnectivity.IsEnabled(ctx) {
- // The choice here of git rev-list is for performance reasons.
- // git fsck --connectivity-only performed badly for large
- // repositories. The reasons are detailed in https://lore.kernel.org/git/9304B938-4A59-456B-B091-DBBCAA1823B2@gmail.com/
- cmd, err = repo.Exec(ctx, git.Command{
- Name: "rev-list",
- Flags: []git.Option{
- git.Flag{Name: "--objects"},
- git.Flag{Name: "--all"},
- git.Flag{Name: "--quiet"},
- },
- })
- } else {
- cmd, err = repo.Exec(ctx, git.Command{
- Name: "fsck",
- Flags: []git.Option{git.Flag{Name: "--connectivity-only"}},
- }, git.WithConfig(git.ConfigPair{
- // Starting with Git's f30e4d854b (fsck: verify commit graph when implicitly
- // enabled, 2021-10-15), git-fsck(1) will check the commit graph for consistency
- // even if `core.commitGraph` is not enabled explicitly. We do not want to verify
- // whether the commit graph is consistent though, but only care about connectivity,
- // so we now explicitly disable usage of the commit graph.
- Key: "core.commitGraph", Value: "false",
- }))
- }
-
+ // The choice here of git rev-list is for performance reasons.
+ // git fsck --connectivity-only performed badly for large
+ // repositories. The reasons are detailed in https://lore.kernel.org/git/9304B938-4A59-456B-B091-DBBCAA1823B2@gmail.com/
+ cmd, err := repo.Exec(ctx, git.Command{
+ Name: "rev-list",
+ Flags: []git.Option{
+ git.Flag{Name: "--objects"},
+ git.Flag{Name: "--all"},
+ git.Flag{Name: "--quiet"},
+ },
+ })
if err != nil {
return err
}
diff --git a/internal/gitaly/service/objectpool/alternates_test.go b/internal/gitaly/service/objectpool/alternates_test.go
index 21fc62db7..bb8351d93 100644
--- a/internal/gitaly/service/objectpool/alternates_test.go
+++ b/internal/gitaly/service/objectpool/alternates_test.go
@@ -1,7 +1,6 @@
package objectpool
import (
- "context"
"os"
"os/exec"
"path/filepath"
@@ -11,7 +10,6 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc/codes"
@@ -20,15 +18,8 @@ import (
func TestDisconnectGitAlternates(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(
- featureflag.RevlistForConnectivity,
- ).Run(
- t,
- testDisconnectGitAlternates,
- )
-}
-func testDisconnectGitAlternates(t *testing.T, ctx context.Context) {
+ ctx := testhelper.Context(t)
cfg, repoProto, repoPath, _, client := setup(t, ctx)
repo := localrepo.NewTestRepo(t, cfg, repoProto)
@@ -67,13 +58,8 @@ func testDisconnectGitAlternates(t *testing.T, ctx context.Context) {
func TestDisconnectGitAlternatesNoAlternates(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.RevlistForConnectivity).Run(
- t,
- testDisconnectGitAlternatesNoAlternates,
- )
-}
-func testDisconnectGitAlternatesNoAlternates(t *testing.T, ctx context.Context) {
+ ctx := testhelper.Context(t)
cfg, repoProto, repoPath, _, client := setup(t, ctx)
repo := localrepo.NewTestRepo(t, cfg, repoProto)
@@ -89,13 +75,8 @@ func testDisconnectGitAlternatesNoAlternates(t *testing.T, ctx context.Context)
func TestDisconnectGitAlternatesUnexpectedAlternates(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.RevlistForConnectivity).Run(
- t,
- testDisconnectGitAlternatesUnexpectedAlternates,
- )
-}
-func testDisconnectGitAlternatesUnexpectedAlternates(t *testing.T, ctx context.Context) {
+ ctx := testhelper.Context(t)
cfg, _, _, _, client := setup(t, ctx)
testCases := []struct {
@@ -127,13 +108,9 @@ func testDisconnectGitAlternatesUnexpectedAlternates(t *testing.T, ctx context.C
func TestRemoveAlternatesIfOk(t *testing.T) {
t.Parallel()
- testhelper.NewFeatureSets(featureflag.RevlistForConnectivity).Run(
- t,
- testRemoveAlternatesIfOk,
- )
-}
-func testRemoveAlternatesIfOk(t *testing.T, ctx context.Context) {
+ ctx := testhelper.Context(t)
+
t.Run("pack files are missing", func(t *testing.T) {
cfg, repoProto, repoPath, _, _ := setup(t, ctx)
srv := server{gitCmdFactory: gittest.NewCommandFactory(t, cfg)}
diff --git a/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go b/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go
index 585eccf11..176555599 100644
--- a/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go
+++ b/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go
@@ -13,14 +13,14 @@ import (
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/operations/apply_patch_test.go b/internal/gitaly/service/operations/apply_patch_test.go
index 54bf80892..09bdeb0a1 100644
--- a/internal/gitaly/service/operations/apply_patch_test.go
+++ b/internal/gitaly/service/operations/apply_patch_test.go
@@ -12,13 +12,13 @@ import (
"time"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/operations/branches_test.go b/internal/gitaly/service/operations/branches_test.go
index a11bedc9a..ed18aa28d 100644
--- a/internal/gitaly/service/operations/branches_test.go
+++ b/internal/gitaly/service/operations/branches_test.go
@@ -10,7 +10,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -18,8 +17,9 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
@@ -31,18 +31,6 @@ import (
"google.golang.org/grpc/status"
)
-type testTransactionServer struct {
- gitalypb.UnimplementedRefTransactionServer
- called int
-}
-
-func (s *testTransactionServer) VoteTransaction(ctx context.Context, in *gitalypb.VoteTransactionRequest) (*gitalypb.VoteTransactionResponse, error) {
- s.called++
- return &gitalypb.VoteTransactionResponse{
- State: gitalypb.VoteTransactionResponse_COMMIT,
- }, nil
-}
-
func TestUserCreateBranch_successful(t *testing.T) {
t.Parallel()
diff --git a/internal/gitaly/service/operations/merge_test.go b/internal/gitaly/service/operations/merge_test.go
index 37c0377f7..d14d60b7b 100644
--- a/internal/gitaly/service/operations/merge_test.go
+++ b/internal/gitaly/service/operations/merge_test.go
@@ -13,7 +13,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -21,6 +20,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/gitaly/service/operations/rebase_test.go b/internal/gitaly/service/operations/rebase_test.go
index 7fee6f34c..8ea7cb2e7 100644
--- a/internal/gitaly/service/operations/rebase_test.go
+++ b/internal/gitaly/service/operations/rebase_test.go
@@ -12,7 +12,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/operations/squash_test.go b/internal/gitaly/service/operations/squash_test.go
index 75eac5a71..41535f731 100644
--- a/internal/gitaly/service/operations/squash_test.go
+++ b/internal/gitaly/service/operations/squash_test.go
@@ -15,8 +15,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/operations/submodules.go b/internal/gitaly/service/operations/submodules.go
index f5daad03c..ba249bcde 100644
--- a/internal/gitaly/service/operations/submodules.go
+++ b/internal/gitaly/service/operations/submodules.go
@@ -86,14 +86,14 @@ func (s *Server) updateSubmodule(ctx context.Context, quarantineRepo *localrepo.
return "", fmt.Errorf("error reading tree: %w", err)
}
- var newEntries []localrepo.TreeEntry
+ var newEntries []*localrepo.TreeEntry
var newTreeID git.ObjectID
for _, entry := range entries {
// If the entry's path does not match, then we simply
// want to retain this tree entry.
if entry.Path != base {
- newEntries = append(newEntries, *entry)
+ newEntries = append(newEntries, entry)
continue
}
@@ -119,7 +119,7 @@ func (s *Server) updateSubmodule(ctx context.Context, quarantineRepo *localrepo.
// Otherwise, create a new tree entry
submoduleFound = true
- newEntries = append(newEntries, localrepo.TreeEntry{
+ newEntries = append(newEntries, &localrepo.TreeEntry{
Mode: entry.Mode,
Path: entry.Path,
OID: replaceWith,
diff --git a/internal/gitaly/service/operations/tags.go b/internal/gitaly/service/operations/tags.go
index 944c9132f..5b0ec9d46 100644
--- a/internal/gitaly/service/operations/tags.go
+++ b/internal/gitaly/service/operations/tags.go
@@ -38,15 +38,21 @@ func (s *Server) UserDeleteTag(ctx context.Context, req *gitalypb.UserDeleteTagR
}
referenceName := git.ReferenceName(fmt.Sprintf("refs/tags/%s", req.TagName))
+ repo := s.localrepo(req.GetRepository())
+
+ objectHash, err := repo.ObjectHash(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("detecting object format: %w", err)
+ }
+
var revision git.ObjectID
- var err error
if expectedOldOID := req.GetExpectedOldOid(); expectedOldOID != "" {
- revision, err = git.ObjectHashSHA1.FromHex(expectedOldOID)
+ revision, err = objectHash.FromHex(expectedOldOID)
if err != nil {
return nil, structerr.NewInvalidArgument("invalid expected old object ID: %w", err).WithMetadata("old_object_id", expectedOldOID)
}
- revision, err = s.localrepo(req.GetRepository()).ResolveRevision(
+ revision, err = repo.ResolveRevision(
ctx, git.Revision(fmt.Sprintf("%s^{object}", revision)),
)
if err != nil {
@@ -54,7 +60,7 @@ func (s *Server) UserDeleteTag(ctx context.Context, req *gitalypb.UserDeleteTagR
WithMetadata("old_object_id", expectedOldOID)
}
} else {
- revision, err = s.localrepo(req.GetRepository()).ResolveRevision(ctx, referenceName.Revision())
+ revision, err = repo.ResolveRevision(ctx, referenceName.Revision())
if err != nil {
if errors.Is(err, git.ErrReferenceNotFound) {
return nil, structerr.NewFailedPrecondition("tag not found: %s", req.TagName)
@@ -63,7 +69,7 @@ func (s *Server) UserDeleteTag(ctx context.Context, req *gitalypb.UserDeleteTagR
}
}
- if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, nil, referenceName, git.ObjectHashSHA1.ZeroOID, revision); err != nil {
+ if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, nil, referenceName, objectHash.ZeroOID, revision); err != nil {
var customHookErr updateref.CustomHookError
if errors.As(err, &customHookErr) {
return &gitalypb.UserDeleteTagResponse{
@@ -129,6 +135,11 @@ func (s *Server) UserCreateTag(ctx context.Context, req *gitalypb.UserCreateTagR
return nil, err
}
+ objectHash, err := quarantineRepo.ObjectHash(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("detecting object hash: %w", err)
+ }
+
tag, tagID, err := s.createTag(ctx, quarantineRepo, targetRevision, req.TagName, req.Message, req.User, committerTime)
if err != nil {
return nil, err
@@ -160,7 +171,7 @@ func (s *Server) UserCreateTag(ctx context.Context, req *gitalypb.UserCreateTagR
)
}
- if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, quarantineDir, referenceName, tagID, git.ObjectHashSHA1.ZeroOID); err != nil {
+ if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, quarantineDir, referenceName, tagID, objectHash.ZeroOID); err != nil {
var notAllowedError hook.NotAllowedError
var customHookErr updateref.CustomHookError
var updateRefError updateref.Error
diff --git a/internal/gitaly/service/operations/tags_test.go b/internal/gitaly/service/operations/tags_test.go
index 661be50a7..952643087 100644
--- a/internal/gitaly/service/operations/tags_test.go
+++ b/internal/gitaly/service/operations/tags_test.go
@@ -1,5 +1,3 @@
-//go:build !gitaly_test_sha256
-
package operations
import (
@@ -10,12 +8,12 @@ import (
"time"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
@@ -250,25 +248,27 @@ func TestUserDeleteTag(t *testing.T) {
func TestUserDeleteTag_hooks(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
-
- ctx, cfg, repo, repoPath, client := setupOperationsService(t, ctx)
- tagNameInput := "to-be-déleted-soon-tag"
-
- request := &gitalypb.UserDeleteTagRequest{
- Repository: repo,
- TagName: []byte(tagNameInput),
- User: gittest.TestUser,
- }
+ ctx := testhelper.Context(t)
+ ctx, cfg, client := setupOperationsServiceWithoutRepo(t, ctx)
for _, hookName := range GitlabHooks {
+ hookName := hookName
+
t.Run(hookName, func(t *testing.T) {
- gittest.Exec(t, cfg, "-C", repoPath, "tag", tagNameInput)
+ t.Parallel()
+
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg)
+ commitID := gittest.WriteCommit(t, cfg, repoPath)
+ gittest.WriteTag(t, cfg, repoPath, "to-be-deleted", commitID.Revision())
hookOutputTempPath := gittest.WriteEnvToCustomHook(t, repoPath, hookName)
- _, err := client.UserDeleteTag(ctx, request)
+ _, err := client.UserDeleteTag(ctx, &gitalypb.UserDeleteTagRequest{
+ Repository: repo,
+ TagName: []byte("to-be-deleted"),
+ User: gittest.TestUser,
+ })
require.NoError(t, err)
output := testhelper.MustReadFile(t, hookOutputTempPath)
@@ -368,8 +368,11 @@ func TestUserCreateTag_successful(t *testing.T) {
message: "This is an annotated tag",
expectedResponse: &gitalypb.UserCreateTagResponse{
Tag: &gitalypb.Tag{
- Name: []byte(inputTagName),
- Id: "6c6134431f05e3d22726a3876cc1fecea7df18b5",
+ Name: []byte(inputTagName),
+ Id: gittest.ObjectHashDependent(t, map[string]string{
+ "sha1": "6c6134431f05e3d22726a3876cc1fecea7df18b5",
+ "sha256": "a9dc4f6d82a3be4e52aad29658cb59e6599498a273d02afac0b4bfd0b79d508d",
+ }),
TargetCommit: targetRevisionCommit,
Message: []byte("This is an annotated tag"),
MessageSize: 24,
@@ -875,10 +878,17 @@ func TestUserCreateTag_nestedTags(t *testing.T) {
t.Parallel()
ctx := testhelper.Context(t)
- ctx, cfg, repoProto, repoPath, client := setupOperationsService(t, ctx)
+ ctx, cfg, client := setupOperationsServiceWithoutRepo(t, ctx)
+ repoProto, repoPath := gittest.CreateRepository(t, ctx, cfg)
repo := localrepo.NewTestRepo(t, cfg, repoProto)
+ blobID := gittest.WriteBlob(t, cfg, repoPath, []byte("content"))
+ treeID := gittest.WriteTree(t, cfg, repoPath, []gittest.TreeEntry{
+ {Path: "blob", Mode: "100644", OID: blobID},
+ })
+ commitID := gittest.WriteCommit(t, cfg, repoPath, gittest.WithTree(treeID))
+
for _, tc := range []struct {
desc string
targetObject string
@@ -887,17 +897,17 @@ func TestUserCreateTag_nestedTags(t *testing.T) {
}{
{
desc: "nested tags to commit",
- targetObject: "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd",
+ targetObject: commitID.String(),
targetObjectType: "commit",
},
{
desc: "nested tags to tree",
targetObjectType: "tree",
- targetObject: "612036fac47c5d31c212b17268e2f3ba807bce1e",
+ targetObject: treeID.String(),
},
{
desc: "nested tags to blob",
- targetObject: "dfaa3f97ca337e20154a98ac9d0be76ddd1fcc82",
+ targetObject: blobID.String(),
targetObjectType: "blob",
},
} {
@@ -1008,7 +1018,10 @@ func TestUserCreateTag_stableTagIDs(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &gitalypb.Tag{
- Id: "d877784c740f492d74e6073de649a6b046ab3656",
+ Id: gittest.ObjectHashDependent(t, map[string]string{
+ "sha1": "d877784c740f492d74e6073de649a6b046ab3656",
+ "sha256": "32397ee1fd84d0b06365045712b658cd2fd265e4d8478fc8186e68555abe4002",
+ }),
Name: []byte("happy-tag"),
Message: []byte("my message"),
MessageSize: 10,
@@ -1093,19 +1106,13 @@ func TestUserCreateTag_gitHooks(t *testing.T) {
func TestUserDeleteTag_hookFailure(t *testing.T) {
t.Parallel()
- ctx := testhelper.Context(t)
- ctx, cfg, repo, repoPath, client := setupOperationsService(t, ctx)
-
- tagNameInput := "to-be-deleted-soon-tag"
- gittest.Exec(t, cfg, "-C", repoPath, "tag", tagNameInput)
- defer gittest.Exec(t, cfg, "-C", repoPath, "tag", "-d", tagNameInput)
+ ctx := testhelper.Context(t)
+ ctx, cfg, client := setupOperationsServiceWithoutRepo(t, ctx)
- request := &gitalypb.UserDeleteTagRequest{
- Repository: repo,
- TagName: []byte(tagNameInput),
- User: gittest.TestUser,
- }
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg)
+ commitID := gittest.WriteCommit(t, cfg, repoPath)
+ gittest.WriteTag(t, cfg, repoPath, "to-be-deleted", commitID.Revision())
hookContent := []byte("#!/bin/sh\necho GL_ID=$GL_ID\nexit 1")
@@ -1113,12 +1120,16 @@ func TestUserDeleteTag_hookFailure(t *testing.T) {
t.Run(hookName, func(t *testing.T) {
gittest.WriteCustomHook(t, repoPath, hookName, hookContent)
- response, err := client.UserDeleteTag(ctx, request)
+ response, err := client.UserDeleteTag(ctx, &gitalypb.UserDeleteTagRequest{
+ Repository: repo,
+ TagName: []byte("to-be-deleted"),
+ User: gittest.TestUser,
+ })
require.NoError(t, err)
require.Contains(t, response.PreReceiveError, "GL_ID="+gittest.TestUser.GlId)
tags := gittest.Exec(t, cfg, "-C", repoPath, "tag")
- require.Contains(t, string(tags), tagNameInput, "tag name does not exist in tags list")
+ require.Contains(t, string(tags), "to-be-deleted", "tag name does not exist in tags list")
})
}
}
@@ -1363,7 +1374,7 @@ func TestTagHookOutput(t *testing.T) {
t.Parallel()
ctx := testhelper.Context(t)
- ctx, cfg, repo, repoPath, client := setupOperationsService(t, ctx)
+ ctx, cfg, client := setupOperationsServiceWithoutRepo(t, ctx)
for _, tc := range []struct {
desc string
@@ -1426,45 +1437,55 @@ func TestTagHookOutput(t *testing.T) {
hookType: gitalypb.CustomHookError_HOOK_TYPE_UPDATE,
},
} {
+ tc := tc
+ hookTC := hookTC
+
t.Run(hookTC.hook+"/"+tc.desc, func(t *testing.T) {
- tagNameInput := "some-tag"
- createRequest := &gitalypb.UserCreateTagRequest{
- Repository: repo,
- TagName: []byte(tagNameInput),
- TargetRevision: []byte("master"),
- User: gittest.TestUser,
- }
- deleteRequest := &gitalypb.UserDeleteTagRequest{
- Repository: repo,
- TagName: []byte(tagNameInput),
- User: gittest.TestUser,
- }
+ t.Parallel()
+
+ repo, repoPath := gittest.CreateRepository(t, ctx, cfg)
+ commitID := gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch(git.DefaultBranch))
+ gittest.WriteTag(t, cfg, repoPath, "to-be-deleted", commitID.Revision())
hookFilename := gittest.WriteCustomHook(t, repoPath, hookTC.hook, []byte(tc.hookContent))
- createResponse, err := client.UserCreateTag(ctx, createRequest)
- testhelper.RequireGrpcError(t, structerr.NewPermissionDenied("reference update denied by custom hooks").WithDetail(
- &gitalypb.UserCreateTagError{
- Error: &gitalypb.UserCreateTagError_CustomHook{
- CustomHook: &gitalypb.CustomHookError{
- HookType: hookTC.hookType,
- Stdout: []byte(tc.expectedStdout),
- Stderr: []byte(tc.expectedStderr),
+ t.Run("UserCreateTag", func(t *testing.T) {
+ t.Parallel()
+
+ response, err := client.UserCreateTag(ctx, &gitalypb.UserCreateTagRequest{
+ Repository: repo,
+ TagName: []byte("new-tag"),
+ TargetRevision: []byte(git.DefaultBranch),
+ User: gittest.TestUser,
+ })
+
+ testhelper.RequireGrpcError(t, structerr.NewPermissionDenied("reference update denied by custom hooks").WithDetail(
+ &gitalypb.UserCreateTagError{
+ Error: &gitalypb.UserCreateTagError_CustomHook{
+ CustomHook: &gitalypb.CustomHookError{
+ HookType: hookTC.hookType,
+ Stdout: []byte(tc.expectedStdout),
+ Stderr: []byte(tc.expectedStderr),
+ },
},
},
- },
- ), err)
- require.Nil(t, createResponse)
-
- defer gittest.Exec(t, cfg, "-C", repoPath, "tag", "-d", tagNameInput)
- gittest.Exec(t, cfg, "-C", repoPath, "tag", tagNameInput)
-
- deleteResponse, err := client.UserDeleteTag(ctx, deleteRequest)
- require.NoError(t, err)
- deleteResponseOk := &gitalypb.UserDeleteTagResponse{
- PreReceiveError: tc.expectedErr(hookFilename),
- }
- testhelper.ProtoEqual(t, deleteResponseOk, deleteResponse)
+ ), err)
+ require.Nil(t, response)
+ })
+
+ t.Run("UserDeleteTag", func(t *testing.T) {
+ t.Parallel()
+
+ response, err := client.UserDeleteTag(ctx, &gitalypb.UserDeleteTagRequest{
+ Repository: repo,
+ TagName: []byte("to-be-deleted"),
+ User: gittest.TestUser,
+ })
+ require.NoError(t, err)
+ testhelper.ProtoEqual(t, &gitalypb.UserDeleteTagResponse{
+ PreReceiveError: tc.expectedErr(hookFilename),
+ }, response)
+ })
})
}
}
diff --git a/internal/gitaly/service/operations/testhelper_test.go b/internal/gitaly/service/operations/testhelper_test.go
index ff6ada770..9e4d5a07d 100644
--- a/internal/gitaly/service/operations/testhelper_test.go
+++ b/internal/gitaly/service/operations/testhelper_test.go
@@ -1,5 +1,3 @@
-//go:build !gitaly_test_sha256
-
package operations
import (
@@ -168,3 +166,15 @@ func setupAndStartGitlabServer(tb testing.TB, glID, glRepository string, cfg con
return url
}
+
+type testTransactionServer struct {
+ gitalypb.UnimplementedRefTransactionServer
+ called int
+}
+
+func (s *testTransactionServer) VoteTransaction(ctx context.Context, in *gitalypb.VoteTransactionRequest) (*gitalypb.VoteTransactionResponse, error) {
+ s.called++
+ return &gitalypb.VoteTransactionResponse{
+ State: gitalypb.VoteTransactionResponse_COMMIT,
+ }, nil
+}
diff --git a/internal/gitaly/service/ref/delete_refs_test.go b/internal/gitaly/service/ref/delete_refs_test.go
index 33c7639ca..831c21663 100644
--- a/internal/gitaly/service/ref/delete_refs_test.go
+++ b/internal/gitaly/service/ref/delete_refs_test.go
@@ -14,7 +14,7 @@ import (
hookservice "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/repository/apply_gitattributes_test.go b/internal/gitaly/service/repository/apply_gitattributes_test.go
index 77923d770..897c20938 100644
--- a/internal/gitaly/service/repository/apply_gitattributes_test.go
+++ b/internal/gitaly/service/repository/apply_gitattributes_test.go
@@ -8,10 +8,10 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/repository/create_repository_from_bundle_test.go b/internal/gitaly/service/repository/create_repository_from_bundle_test.go
index b44f8419a..e25ada641 100644
--- a/internal/gitaly/service/repository/create_repository_from_bundle_test.go
+++ b/internal/gitaly/service/repository/create_repository_from_bundle_test.go
@@ -18,8 +18,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/praefectutil"
"gitlab.com/gitlab-org/gitaly/v16/internal/tempdir"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/gitaly/service/repository/create_repository_test.go b/internal/gitaly/service/repository/create_repository_test.go
index 5f532431d..ed7b1130c 100644
--- a/internal/gitaly/service/repository/create_repository_test.go
+++ b/internal/gitaly/service/repository/create_repository_test.go
@@ -13,8 +13,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/auth"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/praefectutil"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/gitaly/service/repository/fetch_bundle_test.go b/internal/gitaly/service/repository/fetch_bundle_test.go
index e27056ae3..b7eed4669 100644
--- a/internal/gitaly/service/repository/fetch_bundle_test.go
+++ b/internal/gitaly/service/repository/fetch_bundle_test.go
@@ -12,7 +12,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
gitalyhook "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/repository/fetch_remote_test.go b/internal/gitaly/service/repository/fetch_remote_test.go
index b33c0fac4..a14a04e29 100644
--- a/internal/gitaly/service/repository/fetch_remote_test.go
+++ b/internal/gitaly/service/repository/fetch_remote_test.go
@@ -15,9 +15,9 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/repository/license_test.go b/internal/gitaly/service/repository/license_test.go
index 01f1f4f4d..01a703def 100644
--- a/internal/gitaly/service/repository/license_test.go
+++ b/internal/gitaly/service/repository/license_test.go
@@ -9,9 +9,9 @@ import (
"github.com/go-enry/go-license-detector/v4/licensedb"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/repository/optimize_test.go b/internal/gitaly/service/repository/optimize_test.go
index 443be1a6a..f94718a03 100644
--- a/internal/gitaly/service/repository/optimize_test.go
+++ b/internal/gitaly/service/repository/optimize_test.go
@@ -14,13 +14,13 @@ import (
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/housekeeping"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/repository/prune_unreachable_objects.go b/internal/gitaly/service/repository/prune_unreachable_objects.go
index ae5e54a4f..c2ef446ca 100644
--- a/internal/gitaly/service/repository/prune_unreachable_objects.go
+++ b/internal/gitaly/service/repository/prune_unreachable_objects.go
@@ -57,7 +57,7 @@ func (s *server) PruneUnreachableObjects(
if err := housekeeping.RepackObjects(ctx, repo, housekeeping.RepackObjectsConfig{
Strategy: housekeeping.RepackObjectsStrategyFullWithCruft,
WriteMultiPackIndex: true,
- WriteBitmap: len(repoInfo.Alternates) == 0,
+ WriteBitmap: len(repoInfo.Alternates.ObjectDirectories) == 0,
CruftExpireBefore: expireBefore,
}); err != nil {
return nil, structerr.NewInternal("repacking objects: %w", err)
diff --git a/internal/gitaly/service/repository/remove.go b/internal/gitaly/service/repository/remove.go
index abeab649d..299ecb7fb 100644
--- a/internal/gitaly/service/repository/remove.go
+++ b/internal/gitaly/service/repository/remove.go
@@ -2,19 +2,10 @@ package repository
import (
"context"
- "errors"
- "fmt"
- "os"
- "path/filepath"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/repoutil"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
- "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
- "gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
- "gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
- "gitlab.com/gitlab-org/gitaly/v16/internal/transaction/voting"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
@@ -23,91 +14,10 @@ func (s *server) RemoveRepository(ctx context.Context, in *gitalypb.RemoveReposi
if err := service.ValidateRepository(repository); err != nil {
return nil, structerr.NewInvalidArgument("%w", err)
}
- path, err := s.locator.GetPath(repository)
- if err != nil {
- return nil, structerr.NewInternal("%w", err)
- }
-
- tempDir, err := s.locator.TempDir(repository.GetStorageName())
- if err != nil {
- return nil, structerr.NewInternal("temporary directory: %w", err)
- }
-
- if err := os.MkdirAll(tempDir, perm.SharedDir); err != nil {
- return nil, structerr.NewInternal("%w", err)
- }
-
- base := filepath.Base(path)
- destDir := filepath.Join(tempDir, base+"+removed")
-
- // Check whether the repository exists. If not, then there is nothing we can
- // remove. Historically, we didn't return an error in this case, which was just
- // plain bad RPC design: callers should be able to act on this, and if they don't
- // care they may still just return `NotFound` errors.
- if _, err := os.Stat(path); err != nil {
- if os.IsNotExist(err) {
- return nil, structerr.NewNotFound("repository does not exist")
- }
-
- return nil, structerr.NewInternal("statting repository: %w", err)
- }
-
- // Lock the repository such that it cannot be created or removed by any concurrent
- // RPC call.
- unlock, err := repoutil.Lock(ctx, s.locator, repository)
- if err != nil {
- if errors.Is(err, safe.ErrFileAlreadyLocked) {
- return nil, structerr.NewFailedPrecondition("repository is already locked")
- }
- return nil, structerr.NewInternal("locking repository for removal: %w", err)
- }
- defer unlock()
- // Recheck whether the repository still exists after we have taken the lock. It
- // could be a concurrent RPC call removed the repository while we have not yet been
- // holding the lock.
- if _, err := os.Stat(path); err != nil {
- if os.IsNotExist(err) {
- return nil, structerr.NewNotFound("repository was concurrently removed")
- }
- return nil, structerr.NewInternal("re-statting repository: %w", err)
- }
-
- if err := s.voteOnAction(ctx, repository, voting.Prepared); err != nil {
- return nil, structerr.NewInternal("vote on rename: %w", err)
- }
-
- // We move the repository into our temporary directory first before we start to
- // delete it. This is done such that we don't leave behind a partially-removed and
- // thus likely corrupt repository.
- if err := os.Rename(path, destDir); err != nil {
- return nil, structerr.NewInternal("staging repository for removal: %w", err)
- }
-
- if err := os.RemoveAll(destDir); err != nil {
- return nil, structerr.NewInternal("removing repository: %w", err)
- }
-
- if err := s.voteOnAction(ctx, repository, voting.Committed); err != nil {
- return nil, structerr.NewInternal("vote on finalizing: %w", err)
+ if err := repoutil.Remove(ctx, s.locator, s.txManager, repository); err != nil {
+ return nil, err
}
return &gitalypb.RemoveRepositoryResponse{}, nil
}
-
-func (s *server) voteOnAction(ctx context.Context, repo *gitalypb.Repository, phase voting.Phase) error {
- return transaction.RunOnContext(ctx, func(tx txinfo.Transaction) error {
- var voteStep string
- switch phase {
- case voting.Prepared:
- voteStep = "pre-remove"
- case voting.Committed:
- voteStep = "post-remove"
- default:
- return fmt.Errorf("invalid removal step: %d", phase)
- }
-
- vote := fmt.Sprintf("%s %s", voteStep, repo.GetRelativePath())
- return s.txManager.Vote(ctx, tx, voting.VoteFromData([]byte(vote)), phase)
- })
-}
diff --git a/internal/gitaly/service/repository/replicate.go b/internal/gitaly/service/repository/replicate.go
index 32251f386..10ecb3157 100644
--- a/internal/gitaly/service/repository/replicate.go
+++ b/internal/gitaly/service/repository/replicate.go
@@ -20,8 +20,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/tempdir"
diff --git a/internal/gitaly/service/repository/replicate_test.go b/internal/gitaly/service/repository/replicate_test.go
index 640c0d93f..6a90e7560 100644
--- a/internal/gitaly/service/repository/replicate_test.go
+++ b/internal/gitaly/service/repository/replicate_test.go
@@ -17,7 +17,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -26,9 +25,10 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/repoutil"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/repository/set_custom_hooks_test.go b/internal/gitaly/service/repository/set_custom_hooks_test.go
index c1b9579bf..517b31314 100644
--- a/internal/gitaly/service/repository/set_custom_hooks_test.go
+++ b/internal/gitaly/service/repository/set_custom_hooks_test.go
@@ -15,8 +15,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/repoutil"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/repository/write_ref_test.go b/internal/gitaly/service/repository/write_ref_test.go
index 9158f54b7..c12d8d82e 100644
--- a/internal/gitaly/service/repository/write_ref_test.go
+++ b/internal/gitaly/service/repository/write_ref_test.go
@@ -11,8 +11,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/setup/register.go b/internal/gitaly/service/setup/register.go
index 2c40bb220..50f0482c1 100644
--- a/internal/gitaly/service/setup/register.go
+++ b/internal/gitaly/service/setup/register.go
@@ -144,7 +144,12 @@ func RegisterAll(srv *grpc.Server, deps *service.Dependencies) {
deps.GetPackObjectsConcurrencyTracker(),
deps.GetPackObjectsLimiter(),
))
- gitalypb.RegisterInternalGitalyServer(srv, internalgitaly.NewServer(deps.GetCfg().Storages))
+ gitalypb.RegisterInternalGitalyServer(srv, internalgitaly.NewServer(
+ deps.GetCfg().Storages,
+ deps.GetLocator(),
+ deps.GetGitCmdFactory(),
+ deps.GetCatfileCache(),
+ ))
healthpb.RegisterHealthServer(srv, health.NewServer())
reflection.Register(srv)
diff --git a/internal/gitaly/service/smarthttp/inforefs_test.go b/internal/gitaly/service/smarthttp/inforefs_test.go
index e78ec4f32..364f132ba 100644
--- a/internal/gitaly/service/smarthttp/inforefs_test.go
+++ b/internal/gitaly/service/smarthttp/inforefs_test.go
@@ -13,12 +13,12 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/service/smarthttp/receive_pack_test.go b/internal/gitaly/service/smarthttp/receive_pack_test.go
index 7e14ca0eb..5052481cf 100644
--- a/internal/gitaly/service/smarthttp/receive_pack_test.go
+++ b/internal/gitaly/service/smarthttp/receive_pack_test.go
@@ -13,7 +13,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
@@ -21,9 +21,9 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
gitalyhook "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/smarthttp/testhelper_test.go b/internal/gitaly/service/smarthttp/testhelper_test.go
index 823323888..0a9a455b3 100644
--- a/internal/gitaly/service/smarthttp/testhelper_test.go
+++ b/internal/gitaly/service/smarthttp/testhelper_test.go
@@ -6,13 +6,13 @@ import (
"github.com/stretchr/testify/require"
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
hookservice "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/hook"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/objectpool"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/repository"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/gitaly/service/smarthttp/upload_pack.go b/internal/gitaly/service/smarthttp/upload_pack.go
index 7ff667e40..b28f35591 100644
--- a/internal/gitaly/service/smarthttp/upload_pack.go
+++ b/internal/gitaly/service/smarthttp/upload_pack.go
@@ -11,7 +11,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
)
diff --git a/internal/gitaly/service/smarthttp/upload_pack_test.go b/internal/gitaly/service/smarthttp/upload_pack_test.go
index 6ec595b23..c75df1496 100644
--- a/internal/gitaly/service/smarthttp/upload_pack_test.go
+++ b/internal/gitaly/service/smarthttp/upload_pack_test.go
@@ -18,7 +18,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/pktline"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/ssh/receive_pack_test.go b/internal/gitaly/service/ssh/receive_pack_test.go
index 710576f79..365ee7ef6 100644
--- a/internal/gitaly/service/ssh/receive_pack_test.go
+++ b/internal/gitaly/service/ssh/receive_pack_test.go
@@ -12,15 +12,15 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/service/ssh/upload_pack.go b/internal/gitaly/service/ssh/upload_pack.go
index b65f3899e..5392f092f 100644
--- a/internal/gitaly/service/ssh/upload_pack.go
+++ b/internal/gitaly/service/ssh/upload_pack.go
@@ -15,8 +15,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/pktline"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/stream"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/gitaly/service/ssh/upload_pack_test.go b/internal/gitaly/service/ssh/upload_pack_test.go
index d56c8ab0d..811a91303 100644
--- a/internal/gitaly/service/ssh/upload_pack_test.go
+++ b/internal/gitaly/service/ssh/upload_pack_test.go
@@ -16,14 +16,14 @@ import (
promtest "github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/gitaly/transaction/manager.go b/internal/gitaly/transaction/manager.go
index 1cfc7bcb5..b34c448d9 100644
--- a/internal/gitaly/transaction/manager.go
+++ b/internal/gitaly/transaction/manager.go
@@ -10,9 +10,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
internalclient "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/txinfo"
"gitlab.com/gitlab-org/gitaly/v16/internal/transaction/voting"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/gitaly/transaction/manager_test.go b/internal/gitaly/transaction/manager_test.go
index a39a5adc7..b500a73be 100644
--- a/internal/gitaly/transaction/manager_test.go
+++ b/internal/gitaly/transaction/manager_test.go
@@ -6,11 +6,11 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
diff --git a/internal/gitaly/transaction/voting_test.go b/internal/gitaly/transaction/voting_test.go
index c6cb681f5..0116a6b23 100644
--- a/internal/gitaly/transaction/voting_test.go
+++ b/internal/gitaly/transaction/voting_test.go
@@ -8,7 +8,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
"gitlab.com/gitlab-org/gitaly/v16/internal/safe"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/backchannel/backchannel.go b/internal/grpc/backchannel/backchannel.go
index 990e3e5fb..990e3e5fb 100644
--- a/internal/backchannel/backchannel.go
+++ b/internal/grpc/backchannel/backchannel.go
diff --git a/internal/backchannel/backchannel_example_test.go b/internal/grpc/backchannel/backchannel_example_test.go
index dea595fd3..0bc341e6e 100644
--- a/internal/backchannel/backchannel_example_test.go
+++ b/internal/grpc/backchannel/backchannel_example_test.go
@@ -6,8 +6,8 @@ import (
"net"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
diff --git a/internal/backchannel/backchannel_test.go b/internal/grpc/backchannel/backchannel_test.go
index 9ad009a27..a7c8fed6c 100644
--- a/internal/backchannel/backchannel_test.go
+++ b/internal/grpc/backchannel/backchannel_test.go
@@ -13,7 +13,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc"
diff --git a/internal/backchannel/client.go b/internal/grpc/backchannel/client.go
index c4526b7cc..c4526b7cc 100644
--- a/internal/backchannel/client.go
+++ b/internal/grpc/backchannel/client.go
diff --git a/internal/backchannel/registry.go b/internal/grpc/backchannel/registry.go
index 407d770f9..407d770f9 100644
--- a/internal/backchannel/registry.go
+++ b/internal/grpc/backchannel/registry.go
diff --git a/internal/backchannel/server.go b/internal/grpc/backchannel/server.go
index a6fe677ee..a6fe677ee 100644
--- a/internal/backchannel/server.go
+++ b/internal/grpc/backchannel/server.go
diff --git a/internal/dnsresolver/builder.go b/internal/grpc/dnsresolver/builder.go
index eaf1e4299..eaf1e4299 100644
--- a/internal/dnsresolver/builder.go
+++ b/internal/grpc/dnsresolver/builder.go
diff --git a/internal/dnsresolver/builder_test.go b/internal/grpc/dnsresolver/builder_test.go
index 7cbbf711c..7cbbf711c 100644
--- a/internal/dnsresolver/builder_test.go
+++ b/internal/grpc/dnsresolver/builder_test.go
diff --git a/internal/dnsresolver/noop.go b/internal/grpc/dnsresolver/noop.go
index 6197653ed..6197653ed 100644
--- a/internal/dnsresolver/noop.go
+++ b/internal/grpc/dnsresolver/noop.go
diff --git a/internal/dnsresolver/resolver.go b/internal/grpc/dnsresolver/resolver.go
index a6ecf3136..a6ecf3136 100644
--- a/internal/dnsresolver/resolver.go
+++ b/internal/grpc/dnsresolver/resolver.go
diff --git a/internal/dnsresolver/resolver_test.go b/internal/grpc/dnsresolver/resolver_test.go
index 0f05d20e3..0f05d20e3 100644
--- a/internal/dnsresolver/resolver_test.go
+++ b/internal/grpc/dnsresolver/resolver_test.go
diff --git a/internal/dnsresolver/target.go b/internal/grpc/dnsresolver/target.go
index 0e1ac3f8a..0e1ac3f8a 100644
--- a/internal/dnsresolver/target.go
+++ b/internal/grpc/dnsresolver/target.go
diff --git a/internal/dnsresolver/target_test.go b/internal/grpc/dnsresolver/target_test.go
index 36ad9bf49..36ad9bf49 100644
--- a/internal/dnsresolver/target_test.go
+++ b/internal/grpc/dnsresolver/target_test.go
diff --git a/internal/dnsresolver/testhelper_test.go b/internal/grpc/dnsresolver/testhelper_test.go
index eded29045..eded29045 100644
--- a/internal/dnsresolver/testhelper_test.go
+++ b/internal/grpc/dnsresolver/testhelper_test.go
diff --git a/internal/grpcstats/stats.go b/internal/grpc/grpcstats/stats.go
index 89782e538..89782e538 100644
--- a/internal/grpcstats/stats.go
+++ b/internal/grpc/grpcstats/stats.go
diff --git a/internal/grpcstats/stats_test.go b/internal/grpc/grpcstats/stats_test.go
index 84d13930c..84d13930c 100644
--- a/internal/grpcstats/stats_test.go
+++ b/internal/grpc/grpcstats/stats_test.go
diff --git a/internal/grpcstats/testhelper_test.go b/internal/grpc/grpcstats/testhelper_test.go
index f57175b92..f57175b92 100644
--- a/internal/grpcstats/testhelper_test.go
+++ b/internal/grpc/grpcstats/testhelper_test.go
diff --git a/internal/listenmux/mux.go b/internal/grpc/listenmux/mux.go
index f5a1ed67a..f5a1ed67a 100644
--- a/internal/listenmux/mux.go
+++ b/internal/grpc/listenmux/mux.go
diff --git a/internal/listenmux/mux_test.go b/internal/grpc/listenmux/mux_test.go
index 76997c0c1..76997c0c1 100644
--- a/internal/listenmux/mux_test.go
+++ b/internal/grpc/listenmux/mux_test.go
diff --git a/internal/metadata/metadata.go b/internal/grpc/metadata/metadata.go
index 83e6e1247..83e6e1247 100644
--- a/internal/metadata/metadata.go
+++ b/internal/grpc/metadata/metadata.go
diff --git a/internal/metadata/metadata_test.go b/internal/grpc/metadata/metadata_test.go
index 7d716f6a7..7d716f6a7 100644
--- a/internal/metadata/metadata_test.go
+++ b/internal/grpc/metadata/metadata_test.go
diff --git a/internal/middleware/cache/cache.go b/internal/grpc/middleware/cache/cache.go
index cb5fbb219..cb5fbb219 100644
--- a/internal/middleware/cache/cache.go
+++ b/internal/grpc/middleware/cache/cache.go
diff --git a/internal/middleware/cache/cache_test.go b/internal/grpc/middleware/cache/cache_test.go
index 588063474..588063474 100644
--- a/internal/middleware/cache/cache_test.go
+++ b/internal/grpc/middleware/cache/cache_test.go
diff --git a/internal/middleware/cache/export_test.go b/internal/grpc/middleware/cache/export_test.go
index 48c1dab84..48c1dab84 100644
--- a/internal/middleware/cache/export_test.go
+++ b/internal/grpc/middleware/cache/export_test.go
diff --git a/internal/middleware/cache/prometheus.go b/internal/grpc/middleware/cache/prometheus.go
index 2d1790e3f..2d1790e3f 100644
--- a/internal/middleware/cache/prometheus.go
+++ b/internal/grpc/middleware/cache/prometheus.go
diff --git a/internal/middleware/commandstatshandler/commandstatshandler.go b/internal/grpc/middleware/commandstatshandler/commandstatshandler.go
index c1029e1d8..c1029e1d8 100644
--- a/internal/middleware/commandstatshandler/commandstatshandler.go
+++ b/internal/grpc/middleware/commandstatshandler/commandstatshandler.go
diff --git a/internal/middleware/commandstatshandler/commandstatshandler_test.go b/internal/grpc/middleware/commandstatshandler/commandstatshandler_test.go
index b8305d74f..483a2cc3d 100644
--- a/internal/middleware/commandstatshandler/commandstatshandler_test.go
+++ b/internal/grpc/middleware/commandstatshandler/commandstatshandler_test.go
@@ -10,13 +10,13 @@ import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/command"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/ref"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/middleware/featureflag/featureflag_handler.go b/internal/grpc/middleware/featureflag/featureflag_handler.go
index 0bd40a3e6..1342b4d5f 100644
--- a/internal/middleware/featureflag/featureflag_handler.go
+++ b/internal/grpc/middleware/featureflag/featureflag_handler.go
@@ -6,7 +6,7 @@ import (
"strings"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
)
// FieldsProducer adds feature_flags logging fields to gRPC logs. Only enabled flags are available.
diff --git a/internal/middleware/featureflag/featureflag_handler_test.go b/internal/grpc/middleware/featureflag/featureflag_handler_test.go
index b4834d0c6..5df5850af 100644
--- a/internal/middleware/featureflag/featureflag_handler_test.go
+++ b/internal/grpc/middleware/featureflag/featureflag_handler_test.go
@@ -9,8 +9,8 @@ import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"google.golang.org/grpc"
diff --git a/internal/middleware/limithandler/concurrency_limiter.go b/internal/grpc/middleware/limithandler/concurrency_limiter.go
index 1f807d9db..52b4c293b 100644
--- a/internal/middleware/limithandler/concurrency_limiter.go
+++ b/internal/grpc/middleware/limithandler/concurrency_limiter.go
@@ -76,7 +76,6 @@ func (sem *keyedConcurrencyLimiter) acquire(ctx context.Context, limitingKey str
}
}()
default:
- sem.monitor.Dropped(ctx, limitingKey, len(sem.queueTokens), "max_size")
return ErrMaxQueueSize
}
}
@@ -104,10 +103,8 @@ func (sem *keyedConcurrencyLimiter) acquire(ctx context.Context, limitingKey str
case sem.concurrencyTokens <- struct{}{}:
return nil
case <-ticker.C():
- sem.monitor.Dropped(ctx, limitingKey, len(sem.queueTokens), "max_time")
return ErrMaxQueueTime
case <-ctx.Done():
- sem.monitor.Dropped(ctx, limitingKey, len(sem.queueTokens), "other")
return ctx.Err()
}
}
@@ -120,6 +117,11 @@ func (sem *keyedConcurrencyLimiter) release() {
<-sem.concurrencyTokens
}
+// queueLength returns the length of token queue
+func (sem *keyedConcurrencyLimiter) queueLength() int {
+ return len(sem.queueTokens)
+}
+
// ConcurrencyLimiter contains rate limiter state.
type ConcurrencyLimiter struct {
// maxConcurrencyLimit is the maximum number of concurrent calls to the limited function.
@@ -186,18 +188,22 @@ func (c *ConcurrencyLimiter) Limit(ctx context.Context, limitingKey string, f Li
start := time.Now()
if err := sem.acquire(ctx, limitingKey); err != nil {
+ queueTime := time.Since(start)
switch err {
case ErrMaxQueueSize:
+ c.monitor.Dropped(ctx, limitingKey, sem.queueLength(), queueTime, "max_size")
return nil, structerr.NewResourceExhausted("%w", ErrMaxQueueSize).WithDetail(&gitalypb.LimitError{
ErrorMessage: err.Error(),
RetryAfter: durationpb.New(0),
})
case ErrMaxQueueTime:
+ c.monitor.Dropped(ctx, limitingKey, sem.queueLength(), queueTime, "max_time")
return nil, structerr.NewResourceExhausted("%w", ErrMaxQueueTime).WithDetail(&gitalypb.LimitError{
ErrorMessage: err.Error(),
RetryAfter: durationpb.New(0),
})
default:
+ c.monitor.Dropped(ctx, limitingKey, sem.queueLength(), queueTime, "other")
return nil, fmt.Errorf("unexpected error when dequeueing request: %w", err)
}
}
diff --git a/internal/middleware/limithandler/concurrency_limiter_test.go b/internal/grpc/middleware/limithandler/concurrency_limiter_test.go
index 0a0fa0734..02adb7d04 100644
--- a/internal/middleware/limithandler/concurrency_limiter_test.go
+++ b/internal/grpc/middleware/limithandler/concurrency_limiter_test.go
@@ -77,7 +77,7 @@ func (c *counter) Exit(context.Context) {
c.exit++
}
-func (c *counter) Dropped(_ context.Context, _ string, _ int, reason string) {
+func (c *counter) Dropped(_ context.Context, _ string, _ int, _ time.Duration, reason string) {
switch reason {
case "max_time":
c.droppedTime++
diff --git a/internal/middleware/limithandler/middleware.go b/internal/grpc/middleware/limithandler/middleware.go
index c532943a4..c532943a4 100644
--- a/internal/middleware/limithandler/middleware.go
+++ b/internal/grpc/middleware/limithandler/middleware.go
diff --git a/internal/middleware/limithandler/middleware_test.go b/internal/grpc/middleware/limithandler/middleware_test.go
index e3a260f32..bd5f28240 100644
--- a/internal/middleware/limithandler/middleware_test.go
+++ b/internal/grpc/middleware/limithandler/middleware_test.go
@@ -13,8 +13,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/duration"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/middleware/limithandler/monitor.go b/internal/grpc/middleware/limithandler/monitor.go
index da295c563..b251df6d4 100644
--- a/internal/middleware/limithandler/monitor.go
+++ b/internal/grpc/middleware/limithandler/monitor.go
@@ -14,16 +14,16 @@ type ConcurrencyMonitor interface {
Dequeued(ctx context.Context)
Enter(ctx context.Context, acquireTime time.Duration)
Exit(ctx context.Context)
- Dropped(ctx context.Context, key string, length int, message string)
+ Dropped(ctx context.Context, key string, length int, acquireTime time.Duration, message string)
}
type noopConcurrencyMonitor struct{}
-func (c *noopConcurrencyMonitor) Queued(context.Context, string, int) {}
-func (c *noopConcurrencyMonitor) Dequeued(context.Context) {}
-func (c *noopConcurrencyMonitor) Enter(context.Context, time.Duration) {}
-func (c *noopConcurrencyMonitor) Exit(context.Context) {}
-func (c *noopConcurrencyMonitor) Dropped(context.Context, string, int, string) {}
+func (c *noopConcurrencyMonitor) Queued(context.Context, string, int) {}
+func (c *noopConcurrencyMonitor) Dequeued(context.Context) {}
+func (c *noopConcurrencyMonitor) Enter(context.Context, time.Duration) {}
+func (c *noopConcurrencyMonitor) Exit(context.Context) {}
+func (c *noopConcurrencyMonitor) Dropped(context.Context, string, int, time.Duration, string) {}
// NewNoopConcurrencyMonitor returns a noopConcurrencyMonitor
func NewNoopConcurrencyMonitor() ConcurrencyMonitor {
@@ -99,11 +99,12 @@ func (p *PromMonitor) Exit(ctx context.Context) {
}
// Dropped is called when a request is dropped.
-func (p *PromMonitor) Dropped(ctx context.Context, key string, length int, reason string) {
+func (p *PromMonitor) Dropped(ctx context.Context, key string, length int, acquireTime time.Duration, reason string) {
if stats := limitStatsFromContext(ctx); stats != nil {
stats.SetLimitingKey(p.limitingType, key)
stats.SetConcurrencyQueueLength(length)
stats.SetConcurrencyDroppedReason(reason)
+ stats.AddConcurrencyQueueMs(acquireTime.Milliseconds())
}
p.requestsDroppedMetric.WithLabelValues(reason).Inc()
}
diff --git a/internal/grpc/middleware/limithandler/monitor_test.go b/internal/grpc/middleware/limithandler/monitor_test.go
new file mode 100644
index 000000000..3b5d6163f
--- /dev/null
+++ b/internal/grpc/middleware/limithandler/monitor_test.go
@@ -0,0 +1,422 @@
+package limithandler
+
+import (
+ "bytes"
+ "testing"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "github.com/sirupsen/logrus"
+ "github.com/stretchr/testify/require"
+ promconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/prometheus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+)
+
+func TestNewPerRPCPromMonitor(t *testing.T) {
+ system := "gitaly"
+ fullMethod := "fullMethod"
+ createNewMonitor := func() *PromMonitor {
+ acquiringSecondsVec := prometheus.NewHistogramVec(
+ prometheus.HistogramOpts{
+ Name: "acquiring_seconds",
+ Help: "seconds to acquire",
+ Buckets: promconfig.DefaultConfig().GRPCLatencyBuckets,
+ },
+ []string{"system", "grpc_service", "grpc_method"},
+ )
+ inProgressMetric := prometheus.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "in_progress",
+ Help: "requests in progress",
+ },
+ []string{"system", "grpc_service", "grpc_method"},
+ )
+ queuedMetric := prometheus.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "queued",
+ Help: "number of queued requests",
+ },
+ []string{"system", "grpc_service", "grpc_method"},
+ )
+ requestsDroppedMetric := prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "dropped",
+ Help: "number of dropped requests",
+ },
+ []string{
+ "system",
+ "grpc_service",
+ "grpc_method",
+ "reason",
+ },
+ )
+ return newPerRPCPromMonitor(
+ system,
+ fullMethod,
+ queuedMetric,
+ inProgressMetric,
+ acquiringSecondsVec,
+ requestsDroppedMetric,
+ )
+ }
+
+ t.Run("request is dequeued successfully", func(t *testing.T) {
+ rpcMonitor := createNewMonitor()
+ ctx := InitLimitStats(testhelper.Context(t))
+
+ rpcMonitor.Queued(ctx, fullMethod, 5)
+ rpcMonitor.Enter(ctx, time.Second)
+
+ expectedMetrics := `# HELP acquiring_seconds seconds to acquire
+# TYPE acquiring_seconds histogram
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.001"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.005"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.025"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.1"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.5"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1"} 1
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="10"} 1
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="30"} 1
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="60"} 1
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="300"} 1
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1500"} 1
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="+Inf"} 1
+acquiring_seconds_sum{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
+acquiring_seconds_count{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
+# HELP in_progress requests in progress
+# TYPE in_progress gauge
+in_progress{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
+# HELP queued number of queued requests
+# TYPE queued gauge
+queued{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ rpcMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "in_progress",
+ "queued",
+ "dropped",
+ "acquiring_seconds",
+ ))
+
+ stats := limitStatsFromContext(ctx)
+ require.NotNil(t, stats)
+ require.Equal(t, logrus.Fields{
+ "limit.limiting_type": TypePerRPC,
+ "limit.limiting_key": fullMethod,
+ "limit.concurrency_queue_ms": int64(1000),
+ "limit.concurrency_queue_length": 5,
+ }, stats.Fields())
+
+ // After the request exists, in_progress and queued gauge decrease
+ rpcMonitor.Exit(ctx)
+ rpcMonitor.Dequeued(ctx)
+ expectedMetrics = `# HELP acquiring_seconds seconds to acquire
+# HELP in_progress requests in progress
+# TYPE in_progress gauge
+in_progress{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+# HELP queued number of queued requests
+# TYPE queued gauge
+queued{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ rpcMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "in_progress",
+ "queued",
+ ))
+ })
+
+ t.Run("request is dropped after queueing", func(t *testing.T) {
+ rpcMonitor := createNewMonitor()
+ ctx := InitLimitStats(testhelper.Context(t))
+
+ rpcMonitor.Queued(ctx, fullMethod, 5)
+ rpcMonitor.Dropped(ctx, fullMethod, 5, time.Second, "load")
+
+ expectedMetrics := `# HELP acquiring_seconds seconds to acquire
+# TYPE acquiring_seconds histogram
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.001"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.005"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.025"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.1"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.5"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="10"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="30"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="60"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="300"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1500"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="+Inf"} 0
+acquiring_seconds_sum{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+acquiring_seconds_count{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+# HELP dropped number of dropped requests
+# TYPE dropped counter
+dropped{grpc_method="unknown",grpc_service="unknown",reason="load",system="gitaly"} 1
+# HELP in_progress requests in progress
+# TYPE in_progress gauge
+in_progress{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+# HELP queued number of queued requests
+# TYPE queued gauge
+queued{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ rpcMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "in_progress",
+ "queued",
+ "dropped",
+ "acquiring_seconds",
+ ))
+
+ stats := limitStatsFromContext(ctx)
+ require.NotNil(t, stats)
+ require.Equal(t, logrus.Fields{
+ "limit.limiting_type": TypePerRPC,
+ "limit.limiting_key": fullMethod,
+ "limit.concurrency_queue_ms": int64(1000),
+ "limit.concurrency_queue_length": 5,
+ "limit.concurrency_dropped": "load",
+ }, stats.Fields())
+ })
+
+ t.Run("request is dropped before queueing", func(t *testing.T) {
+ rpcMonitor := createNewMonitor()
+ ctx := InitLimitStats(testhelper.Context(t))
+ rpcMonitor.Dropped(ctx, fullMethod, 5, time.Second, "load")
+
+ expectedMetrics := `# HELP acquiring_seconds seconds to acquire
+# TYPE acquiring_seconds histogram
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.001"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.005"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.025"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.1"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.5"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="10"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="30"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="60"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="300"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1500"} 0
+acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="+Inf"} 0
+acquiring_seconds_sum{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+acquiring_seconds_count{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+# HELP dropped number of dropped requests
+# TYPE dropped counter
+dropped{grpc_method="unknown",grpc_service="unknown",reason="load",system="gitaly"} 1
+# HELP in_progress requests in progress
+# TYPE in_progress gauge
+in_progress{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+# HELP queued number of queued requests
+# TYPE queued gauge
+queued{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 0
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ rpcMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "in_progress",
+ "queued",
+ "dropped",
+ "acquiring_seconds",
+ ))
+
+ stats := limitStatsFromContext(ctx)
+ require.NotNil(t, stats)
+ require.Equal(t, logrus.Fields{
+ "limit.limiting_type": TypePerRPC,
+ "limit.limiting_key": fullMethod,
+ "limit.concurrency_queue_ms": int64(1000),
+ "limit.concurrency_queue_length": 5,
+ "limit.concurrency_dropped": "load",
+ }, stats.Fields())
+ })
+}
+
+func TestNewPackObjectsConcurrencyMonitor(t *testing.T) {
+ t.Run("request is dequeued successfully", func(t *testing.T) {
+ ctx := InitLimitStats(testhelper.Context(t))
+ packObjectsConcurrencyMonitor := NewPackObjectsConcurrencyMonitor(
+ promconfig.DefaultConfig().GRPCLatencyBuckets,
+ )
+
+ packObjectsConcurrencyMonitor.Queued(ctx, "1234", 5)
+ packObjectsConcurrencyMonitor.Enter(ctx, time.Second)
+
+ expectedMetrics := `# HELP gitaly_pack_objects_acquiring_seconds Histogram of time calls are rate limited (in seconds)
+# TYPE gitaly_pack_objects_acquiring_seconds histogram
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.001"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.005"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.025"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.1"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.5"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="1"} 1
+gitaly_pack_objects_acquiring_seconds_bucket{le="10"} 1
+gitaly_pack_objects_acquiring_seconds_bucket{le="30"} 1
+gitaly_pack_objects_acquiring_seconds_bucket{le="60"} 1
+gitaly_pack_objects_acquiring_seconds_bucket{le="300"} 1
+gitaly_pack_objects_acquiring_seconds_bucket{le="1500"} 1
+gitaly_pack_objects_acquiring_seconds_bucket{le="+Inf"} 1
+gitaly_pack_objects_acquiring_seconds_sum 1
+gitaly_pack_objects_acquiring_seconds_count 1
+# HELP gitaly_pack_objects_in_progress Gauge of number of concurrent in-progress calls
+# TYPE gitaly_pack_objects_in_progress gauge
+gitaly_pack_objects_in_progress 1
+# HELP gitaly_pack_objects_queued Gauge of number of queued calls
+# TYPE gitaly_pack_objects_queued gauge
+gitaly_pack_objects_queued 1
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ packObjectsConcurrencyMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "gitaly_pack_objects_acquiring_seconds",
+ "gitaly_pack_objects_in_progress",
+ "gitaly_pack_objects_queued",
+ "gitaly_pack_objects_dropped_total",
+ ))
+
+ stats := limitStatsFromContext(ctx)
+ require.NotNil(t, stats)
+ require.Equal(t, logrus.Fields{
+ "limit.limiting_type": TypePackObjects,
+ "limit.limiting_key": "1234",
+ "limit.concurrency_queue_ms": int64(1000),
+ "limit.concurrency_queue_length": 5,
+ }, stats.Fields())
+
+ // After the request exists, in_progress and queued gauge decrease
+ packObjectsConcurrencyMonitor.Exit(ctx)
+ packObjectsConcurrencyMonitor.Dequeued(ctx)
+ expectedMetrics = `# HELP acquiring_seconds seconds to acquire
+# HELP gitaly_pack_objects_in_progress Gauge of number of concurrent in-progress calls
+# TYPE gitaly_pack_objects_in_progress gauge
+gitaly_pack_objects_in_progress 0
+# HELP gitaly_pack_objects_queued Gauge of number of queued calls
+# TYPE gitaly_pack_objects_queued gauge
+gitaly_pack_objects_queued 0
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ packObjectsConcurrencyMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "gitaly_pack_objects_in_progress",
+ "gitaly_pack_objects_queued",
+ ))
+ })
+
+ t.Run("request is dropped after queueing", func(t *testing.T) {
+ ctx := InitLimitStats(testhelper.Context(t))
+ packObjectsConcurrencyMonitor := NewPackObjectsConcurrencyMonitor(
+ promconfig.DefaultConfig().GRPCLatencyBuckets,
+ )
+
+ packObjectsConcurrencyMonitor.Queued(ctx, "1234", 5)
+ packObjectsConcurrencyMonitor.Dropped(ctx, "1234", 5, time.Second, "load")
+
+ expectedMetrics := `# HELP gitaly_pack_objects_acquiring_seconds Histogram of time calls are rate limited (in seconds)
+# TYPE gitaly_pack_objects_acquiring_seconds histogram
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.001"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.005"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.025"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.1"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.5"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="1"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="10"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="30"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="60"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="300"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="1500"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="+Inf"} 0
+gitaly_pack_objects_acquiring_seconds_sum 0
+gitaly_pack_objects_acquiring_seconds_count 0
+# HELP gitaly_pack_objects_dropped_total Number of requests dropped from the queue
+# TYPE gitaly_pack_objects_dropped_total counter
+gitaly_pack_objects_dropped_total{reason="load"} 1
+# HELP gitaly_pack_objects_in_progress Gauge of number of concurrent in-progress calls
+# TYPE gitaly_pack_objects_in_progress gauge
+gitaly_pack_objects_in_progress 0
+# HELP gitaly_pack_objects_queued Gauge of number of queued calls
+# TYPE gitaly_pack_objects_queued gauge
+gitaly_pack_objects_queued 1
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ packObjectsConcurrencyMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "gitaly_pack_objects_acquiring_seconds",
+ "gitaly_pack_objects_in_progress",
+ "gitaly_pack_objects_queued",
+ "gitaly_pack_objects_dropped_total",
+ ))
+
+ stats := limitStatsFromContext(ctx)
+ require.NotNil(t, stats)
+ require.Equal(t, logrus.Fields{
+ "limit.limiting_type": TypePackObjects,
+ "limit.limiting_key": "1234",
+ "limit.concurrency_queue_ms": int64(1000),
+ "limit.concurrency_queue_length": 5,
+ "limit.concurrency_dropped": "load",
+ }, stats.Fields())
+ })
+
+ t.Run("request is dropped before queueing", func(t *testing.T) {
+ ctx := InitLimitStats(testhelper.Context(t))
+ packObjectsConcurrencyMonitor := NewPackObjectsConcurrencyMonitor(
+ promconfig.DefaultConfig().GRPCLatencyBuckets,
+ )
+
+ packObjectsConcurrencyMonitor.Dropped(ctx, "1234", 5, time.Second, "load")
+
+ expectedMetrics := `# HELP gitaly_pack_objects_acquiring_seconds Histogram of time calls are rate limited (in seconds)
+# TYPE gitaly_pack_objects_acquiring_seconds histogram
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.001"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.005"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.025"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.1"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="0.5"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="1"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="10"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="30"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="60"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="300"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="1500"} 0
+gitaly_pack_objects_acquiring_seconds_bucket{le="+Inf"} 0
+gitaly_pack_objects_acquiring_seconds_sum 0
+gitaly_pack_objects_acquiring_seconds_count 0
+# HELP gitaly_pack_objects_dropped_total Number of requests dropped from the queue
+# TYPE gitaly_pack_objects_dropped_total counter
+gitaly_pack_objects_dropped_total{reason="load"} 1
+# HELP gitaly_pack_objects_in_progress Gauge of number of concurrent in-progress calls
+# TYPE gitaly_pack_objects_in_progress gauge
+gitaly_pack_objects_in_progress 0
+# HELP gitaly_pack_objects_queued Gauge of number of queued calls
+# TYPE gitaly_pack_objects_queued gauge
+gitaly_pack_objects_queued 0
+
+`
+ require.NoError(t, testutil.CollectAndCompare(
+ packObjectsConcurrencyMonitor,
+ bytes.NewBufferString(expectedMetrics),
+ "gitaly_pack_objects_acquiring_seconds",
+ "gitaly_pack_objects_in_progress",
+ "gitaly_pack_objects_queued",
+ "gitaly_pack_objects_dropped_total",
+ ))
+
+ stats := limitStatsFromContext(ctx)
+ require.NotNil(t, stats)
+ require.Equal(t, logrus.Fields{
+ "limit.limiting_type": TypePackObjects,
+ "limit.limiting_key": "1234",
+ "limit.concurrency_queue_ms": int64(1000),
+ "limit.concurrency_queue_length": 5,
+ "limit.concurrency_dropped": "load",
+ }, stats.Fields())
+ })
+}
diff --git a/internal/middleware/limithandler/rate_limiter.go b/internal/grpc/middleware/limithandler/rate_limiter.go
index be09a1f77..be09a1f77 100644
--- a/internal/middleware/limithandler/rate_limiter.go
+++ b/internal/grpc/middleware/limithandler/rate_limiter.go
diff --git a/internal/middleware/limithandler/rate_limiter_test.go b/internal/grpc/middleware/limithandler/rate_limiter_test.go
index 5e88b8f6b..5e88b8f6b 100644
--- a/internal/middleware/limithandler/rate_limiter_test.go
+++ b/internal/grpc/middleware/limithandler/rate_limiter_test.go
diff --git a/internal/middleware/limithandler/stats.go b/internal/grpc/middleware/limithandler/stats.go
index 30926695a..30926695a 100644
--- a/internal/middleware/limithandler/stats.go
+++ b/internal/grpc/middleware/limithandler/stats.go
diff --git a/internal/middleware/limithandler/stats_interceptor_test.go b/internal/grpc/middleware/limithandler/stats_interceptor_test.go
index 0c8ac400c..010e487c8 100644
--- a/internal/middleware/limithandler/stats_interceptor_test.go
+++ b/internal/grpc/middleware/limithandler/stats_interceptor_test.go
@@ -10,14 +10,14 @@ import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/ref"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
diff --git a/internal/middleware/limithandler/stats_test.go b/internal/grpc/middleware/limithandler/stats_test.go
index 53ccccfd5..53ccccfd5 100644
--- a/internal/middleware/limithandler/stats_test.go
+++ b/internal/grpc/middleware/limithandler/stats_test.go
diff --git a/internal/middleware/limithandler/testhelper_test.go b/internal/grpc/middleware/limithandler/testhelper_test.go
index 137c47cce..137c47cce 100644
--- a/internal/middleware/limithandler/testhelper_test.go
+++ b/internal/grpc/middleware/limithandler/testhelper_test.go
diff --git a/internal/middleware/metadatahandler/metadatahandler.go b/internal/grpc/middleware/metadatahandler/metadatahandler.go
index bae12151e..bae12151e 100644
--- a/internal/middleware/metadatahandler/metadatahandler.go
+++ b/internal/grpc/middleware/metadatahandler/metadatahandler.go
diff --git a/internal/middleware/metadatahandler/metadatahandler_test.go b/internal/grpc/middleware/metadatahandler/metadatahandler_test.go
index 7f665574f..7f665574f 100644
--- a/internal/middleware/metadatahandler/metadatahandler_test.go
+++ b/internal/grpc/middleware/metadatahandler/metadatahandler_test.go
diff --git a/internal/middleware/panichandler/LICENSE b/internal/grpc/middleware/panichandler/LICENSE
index b1bb8825b..b1bb8825b 100644
--- a/internal/middleware/panichandler/LICENSE
+++ b/internal/grpc/middleware/panichandler/LICENSE
diff --git a/internal/middleware/panichandler/README.md b/internal/grpc/middleware/panichandler/README.md
index 03b32ec15..03b32ec15 100644
--- a/internal/middleware/panichandler/README.md
+++ b/internal/grpc/middleware/panichandler/README.md
diff --git a/internal/middleware/panichandler/panic_handler.go b/internal/grpc/middleware/panichandler/panic_handler.go
index e91269d5f..e91269d5f 100644
--- a/internal/middleware/panichandler/panic_handler.go
+++ b/internal/grpc/middleware/panichandler/panic_handler.go
diff --git a/internal/middleware/sentryhandler/sentryhandler.go b/internal/grpc/middleware/sentryhandler/sentryhandler.go
index a6645c552..a6645c552 100644
--- a/internal/middleware/sentryhandler/sentryhandler.go
+++ b/internal/grpc/middleware/sentryhandler/sentryhandler.go
diff --git a/internal/middleware/sentryhandler/sentryhandler_test.go b/internal/grpc/middleware/sentryhandler/sentryhandler_test.go
index 7a98e22ea..7a98e22ea 100644
--- a/internal/middleware/sentryhandler/sentryhandler_test.go
+++ b/internal/grpc/middleware/sentryhandler/sentryhandler_test.go
diff --git a/internal/middleware/statushandler/statushandler.go b/internal/grpc/middleware/statushandler/statushandler.go
index 07b736d97..07b736d97 100644
--- a/internal/middleware/statushandler/statushandler.go
+++ b/internal/grpc/middleware/statushandler/statushandler.go
diff --git a/internal/middleware/statushandler/statushandler_test.go b/internal/grpc/middleware/statushandler/statushandler_test.go
index 077806ba5..077806ba5 100644
--- a/internal/middleware/statushandler/statushandler_test.go
+++ b/internal/grpc/middleware/statushandler/statushandler_test.go
diff --git a/internal/praefect/grpc-proxy/LICENSE.txt b/internal/grpc/proxy/LICENSE.txt
index cbfdef8c5..cbfdef8c5 100644
--- a/internal/praefect/grpc-proxy/LICENSE.txt
+++ b/internal/grpc/proxy/LICENSE.txt
diff --git a/internal/praefect/grpc-proxy/proxy/codec.go b/internal/grpc/proxy/codec.go
index 65501a418..65501a418 100644
--- a/internal/praefect/grpc-proxy/proxy/codec.go
+++ b/internal/grpc/proxy/codec.go
diff --git a/internal/praefect/grpc-proxy/proxy/codec_test.go b/internal/grpc/proxy/codec_test.go
index cfa6a05b7..cfa6a05b7 100644
--- a/internal/praefect/grpc-proxy/proxy/codec_test.go
+++ b/internal/grpc/proxy/codec_test.go
diff --git a/internal/praefect/grpc-proxy/proxy/director.go b/internal/grpc/proxy/director.go
index b7aa280ab..b7aa280ab 100644
--- a/internal/praefect/grpc-proxy/proxy/director.go
+++ b/internal/grpc/proxy/director.go
diff --git a/internal/praefect/grpc-proxy/proxy/doc.go b/internal/grpc/proxy/doc.go
index 01328f332..01328f332 100644
--- a/internal/praefect/grpc-proxy/proxy/doc.go
+++ b/internal/grpc/proxy/doc.go
diff --git a/internal/praefect/grpc-proxy/proxy/handler.go b/internal/grpc/proxy/handler.go
index 25dbed58e..eccaf00f5 100644
--- a/internal/praefect/grpc-proxy/proxy/handler.go
+++ b/internal/grpc/proxy/handler.go
@@ -9,7 +9,7 @@ import (
"fmt"
"io"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/sentryhandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/sentryhandler"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
diff --git a/internal/praefect/grpc-proxy/proxy/handler_ext_test.go b/internal/grpc/proxy/handler_ext_test.go
index ec7a8685a..bfa1236c5 100644
--- a/internal/praefect/grpc-proxy/proxy/handler_ext_test.go
+++ b/internal/grpc/proxy/handler_ext_test.go
@@ -19,8 +19,8 @@ import (
"github.com/getsentry/sentry-go"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"google.golang.org/grpc"
diff --git a/internal/praefect/grpc-proxy/proxy/handler_test.go b/internal/grpc/proxy/handler_test.go
index b88501eb2..b88501eb2 100644
--- a/internal/praefect/grpc-proxy/proxy/handler_test.go
+++ b/internal/grpc/proxy/handler_test.go
diff --git a/internal/praefect/grpc-proxy/proxy/peeker.go b/internal/grpc/proxy/peeker.go
index 6825d7f37..6825d7f37 100644
--- a/internal/praefect/grpc-proxy/proxy/peeker.go
+++ b/internal/grpc/proxy/peeker.go
diff --git a/internal/praefect/grpc-proxy/proxy/peeker_test.go b/internal/grpc/proxy/peeker_test.go
index a38629db1..aea17bba2 100644
--- a/internal/praefect/grpc-proxy/proxy/peeker_test.go
+++ b/internal/grpc/proxy/peeker_test.go
@@ -6,8 +6,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"google.golang.org/grpc/interop/grpc_testing"
"google.golang.org/protobuf/proto"
diff --git a/internal/praefect/grpc-proxy/proxy/testhelper_test.go b/internal/grpc/proxy/testhelper_test.go
index 929e8e4f3..5efcfa265 100644
--- a/internal/praefect/grpc-proxy/proxy/testhelper_test.go
+++ b/internal/grpc/proxy/testhelper_test.go
@@ -7,9 +7,9 @@ import (
grpcmwtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/sentryhandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/fieldextractors"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/sentryhandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
diff --git a/internal/sidechannel/conn.go b/internal/grpc/sidechannel/conn.go
index f77bbcbe3..f77bbcbe3 100644
--- a/internal/sidechannel/conn.go
+++ b/internal/grpc/sidechannel/conn.go
diff --git a/internal/sidechannel/conn_test.go b/internal/grpc/sidechannel/conn_test.go
index 257fd4273..257fd4273 100644
--- a/internal/sidechannel/conn_test.go
+++ b/internal/grpc/sidechannel/conn_test.go
diff --git a/internal/sidechannel/proxy.go b/internal/grpc/sidechannel/proxy.go
index 30bebbae1..e7b750b1e 100644
--- a/internal/sidechannel/proxy.go
+++ b/internal/grpc/sidechannel/proxy.go
@@ -5,7 +5,7 @@ import (
"fmt"
"io"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"google.golang.org/grpc"
grpcMetadata "google.golang.org/grpc/metadata"
)
diff --git a/internal/sidechannel/proxy_test.go b/internal/grpc/sidechannel/proxy_test.go
index 8191d1b99..7ab65bb1f 100644
--- a/internal/sidechannel/proxy_test.go
+++ b/internal/grpc/sidechannel/proxy_test.go
@@ -9,9 +9,9 @@ import (
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc"
diff --git a/internal/sidechannel/registry.go b/internal/grpc/sidechannel/registry.go
index 3148cb05d..3148cb05d 100644
--- a/internal/sidechannel/registry.go
+++ b/internal/grpc/sidechannel/registry.go
diff --git a/internal/sidechannel/registry_test.go b/internal/grpc/sidechannel/registry_test.go
index a0b55c2ac..a0b55c2ac 100644
--- a/internal/sidechannel/registry_test.go
+++ b/internal/grpc/sidechannel/registry_test.go
diff --git a/internal/sidechannel/sidechannel.go b/internal/grpc/sidechannel/sidechannel.go
index 1eff50c99..1cc197b8b 100644
--- a/internal/sidechannel/sidechannel.go
+++ b/internal/grpc/sidechannel/sidechannel.go
@@ -10,9 +10,9 @@ import (
"time"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/tracing"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
diff --git a/internal/sidechannel/sidechannel_test.go b/internal/grpc/sidechannel/sidechannel_test.go
index d274f8d8c..ddf6a640c 100644
--- a/internal/sidechannel/sidechannel_test.go
+++ b/internal/grpc/sidechannel/sidechannel_test.go
@@ -10,8 +10,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
diff --git a/internal/log/log_test.go b/internal/log/log_test.go
index dc927ae15..cd3063490 100644
--- a/internal/log/log_test.go
+++ b/internal/log/log_test.go
@@ -18,7 +18,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/grpcstats"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/grpcstats"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/interop/grpc_testing"
diff --git a/internal/metadata/featureflag/ff_revlist_for_connectivity.go b/internal/metadata/featureflag/ff_revlist_for_connectivity.go
deleted file mode 100644
index 09c667fb4..000000000
--- a/internal/metadata/featureflag/ff_revlist_for_connectivity.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package featureflag
-
-// RevlistForConnectivity causes the connectivity check when removing alternates
-// files to use git-rev-list instead of git-fsck
-var RevlistForConnectivity = NewFeatureFlag(
- "revlist_for_connectivity",
- "v15.5.0",
- "https://gitlab.com/gitlab-org/gitaly/-/issues/4489",
- false,
-)
diff --git a/internal/middleware/limithandler/monitor_test.go b/internal/middleware/limithandler/monitor_test.go
deleted file mode 100644
index 1c5eb9dbf..000000000
--- a/internal/middleware/limithandler/monitor_test.go
+++ /dev/null
@@ -1,169 +0,0 @@
-package limithandler
-
-import (
- "bytes"
- "testing"
- "time"
-
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/testutil"
- "github.com/sirupsen/logrus"
- "github.com/stretchr/testify/require"
- promconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/prometheus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
-)
-
-func TestNewPerRPCPromMonitor(t *testing.T) {
- system := "gitaly"
- fullMethod := "fullMethod"
- acquiringSecondsVec := prometheus.NewHistogramVec(
- prometheus.HistogramOpts{
- Name: "acquiring_seconds",
- Help: "seconds to acquire",
- Buckets: promconfig.DefaultConfig().GRPCLatencyBuckets,
- },
- []string{"system", "grpc_service", "grpc_method"},
- )
- inProgressMetric := prometheus.NewGaugeVec(
- prometheus.GaugeOpts{
- Name: "in_progress",
- Help: "requests in progress",
- },
- []string{"system", "grpc_service", "grpc_method"},
- )
- queuedMetric := prometheus.NewGaugeVec(
- prometheus.GaugeOpts{
- Name: "queued",
- Help: "number of queued requests",
- },
- []string{"system", "grpc_service", "grpc_method"},
- )
- requestsDroppedMetric := prometheus.NewCounterVec(
- prometheus.CounterOpts{
- Name: "dropped",
- Help: "number of dropped requests",
- },
- []string{
- "system",
- "grpc_service",
- "grpc_method",
- "reason",
- },
- )
-
- rpcMonitor := newPerRPCPromMonitor(
- system,
- fullMethod,
- queuedMetric,
- inProgressMetric,
- acquiringSecondsVec,
- requestsDroppedMetric,
- )
-
- ctx := InitLimitStats(testhelper.Context(t))
-
- rpcMonitor.Queued(ctx, fullMethod, 5)
- rpcMonitor.Enter(ctx, time.Second)
- rpcMonitor.Dropped(ctx, fullMethod, 5, "load")
-
- expectedMetrics := `# HELP acquiring_seconds seconds to acquire
-# TYPE acquiring_seconds histogram
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.001"} 0
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.005"} 0
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.025"} 0
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.1"} 0
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="0.5"} 0
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1"} 1
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="10"} 1
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="30"} 1
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="60"} 1
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="300"} 1
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="1500"} 1
-acquiring_seconds_bucket{grpc_method="unknown",grpc_service="unknown",system="gitaly",le="+Inf"} 1
-acquiring_seconds_sum{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
-acquiring_seconds_count{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
-# HELP dropped number of dropped requests
-# TYPE dropped counter
-dropped{grpc_method="unknown",grpc_service="unknown",reason="load",system="gitaly"} 1
-# HELP in_progress requests in progress
-# TYPE in_progress gauge
-in_progress{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
-# HELP queued number of queued requests
-# TYPE queued gauge
-queued{grpc_method="unknown",grpc_service="unknown",system="gitaly"} 1
-
-`
- require.NoError(t, testutil.CollectAndCompare(
- rpcMonitor,
- bytes.NewBufferString(expectedMetrics),
- "in_progress",
- "queued",
- "dropped",
- "acquiring_seconds",
- ))
-
- stats := limitStatsFromContext(ctx)
- require.NotNil(t, stats)
- require.Equal(t, logrus.Fields{
- "limit.limiting_type": TypePerRPC,
- "limit.limiting_key": fullMethod,
- "limit.concurrency_queue_ms": int64(1000),
- "limit.concurrency_queue_length": 5,
- "limit.concurrency_dropped": "load",
- }, stats.Fields())
-}
-
-func TestNewPackObjectsConcurrencyMonitor(t *testing.T) {
- ctx := InitLimitStats(testhelper.Context(t))
-
- m := NewPackObjectsConcurrencyMonitor(
- promconfig.DefaultConfig().GRPCLatencyBuckets,
- )
-
- m.Queued(ctx, "1234", 5)
- m.Enter(ctx, time.Second)
- m.Dropped(ctx, "1234", 5, "load")
-
- expectedMetrics := `# HELP gitaly_pack_objects_acquiring_seconds Histogram of time calls are rate limited (in seconds)
-# TYPE gitaly_pack_objects_acquiring_seconds histogram
-gitaly_pack_objects_acquiring_seconds_bucket{le="0.001"} 0
-gitaly_pack_objects_acquiring_seconds_bucket{le="0.005"} 0
-gitaly_pack_objects_acquiring_seconds_bucket{le="0.025"} 0
-gitaly_pack_objects_acquiring_seconds_bucket{le="0.1"} 0
-gitaly_pack_objects_acquiring_seconds_bucket{le="0.5"} 0
-gitaly_pack_objects_acquiring_seconds_bucket{le="1"} 1
-gitaly_pack_objects_acquiring_seconds_bucket{le="10"} 1
-gitaly_pack_objects_acquiring_seconds_bucket{le="30"} 1
-gitaly_pack_objects_acquiring_seconds_bucket{le="60"} 1
-gitaly_pack_objects_acquiring_seconds_bucket{le="300"} 1
-gitaly_pack_objects_acquiring_seconds_bucket{le="1500"} 1
-gitaly_pack_objects_acquiring_seconds_bucket{le="+Inf"} 1
-gitaly_pack_objects_acquiring_seconds_sum 1
-gitaly_pack_objects_acquiring_seconds_count 1
-# HELP gitaly_pack_objects_dropped_total Number of requests dropped from the queue
-# TYPE gitaly_pack_objects_dropped_total counter
-gitaly_pack_objects_dropped_total{reason="load"} 1
-# HELP gitaly_pack_objects_queued Gauge of number of queued calls
-# TYPE gitaly_pack_objects_queued gauge
-gitaly_pack_objects_queued 1
-
-`
- require.NoError(t, testutil.CollectAndCompare(
- m,
- bytes.NewBufferString(expectedMetrics),
- "gitaly_pack_objects_acquiring_seconds",
- "gitaly_pack_objecfts_in_progress",
- "gitaly_pack_objects_queued",
- "gitaly_pack_objects_dropped_total",
- ))
-
- stats := limitStatsFromContext(ctx)
- require.NotNil(t, stats)
- require.Equal(t, logrus.Fields{
- "limit.limiting_type": TypePackObjects,
- "limit.limiting_key": "1234",
- "limit.concurrency_queue_ms": int64(1000),
- "limit.concurrency_queue_length": 5,
- "limit.concurrency_dropped": "load",
- }, stats.Fields())
-}
diff --git a/internal/praefect/coordinator.go b/internal/praefect/coordinator.go
index 2431fa058..24eb35825 100644
--- a/internal/praefect/coordinator.go
+++ b/internal/praefect/coordinator.go
@@ -11,14 +11,14 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
gitalyerrors "gitlab.com/gitlab-org/gitaly/v16/internal/errors"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/metrics"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
diff --git a/internal/praefect/coordinator_test.go b/internal/praefect/coordinator_test.go
index 946ed5161..9106176c9 100644
--- a/internal/praefect/coordinator_test.go
+++ b/internal/praefect/coordinator_test.go
@@ -23,16 +23,16 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
"gitlab.com/gitlab-org/gitaly/v16/internal/datastructure"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
gconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
- gitaly_metadata "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
+ gitaly_metadata "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/transactions"
diff --git a/internal/praefect/grpc-proxy/README.md b/internal/praefect/grpc-proxy/README.md
deleted file mode 100644
index b5f1a3168..000000000
--- a/internal/praefect/grpc-proxy/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# gRPC Proxy
-
-[![Travis Build](https://travis-ci.org/mwitkow/grpc-proxy.svg?branch=master)](https://travis-ci.org/mwitkow/grpc-proxy)
-[![Go Report Card](https://goreportcard.com/badge/github.com/mwitkow/grpc-proxy)](https://goreportcard.com/report/github.com/mwitkow/grpc-proxy)
-[![GoDoc](http://img.shields.io/badge/GoDoc-Reference-blue.svg)](https://godoc.org/github.com/mwitkow/grpc-proxy)
-[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
-
-[gRPC Go](https://github.com/grpc/grpc-go) Proxy server
-
-## Project Goal
-
-Build a transparent reverse proxy for gRPC targets that will make it easy to expose gRPC services
-over the internet. This includes:
- * no needed knowledge of the semantics of requests exchanged in the call (independent rollouts)
- * easy, declarative definition of backends and their mappings to frontends
- * simple round-robin load balancing of inbound requests from a single connection to multiple backends
-
-The project now exists as a **proof of concept**, with the key piece being the `proxy` package that
-is a generic gRPC reverse proxy handler.
-
-## Proxy Handler
-
-The package [`proxy`](proxy/) contains a generic gRPC reverse proxy handler that allows a gRPC server to
-not know about registered handlers or their data types. Please consult the docs, here's an example usage.
-
-Defining a `StreamDirector` that decides where (if at all) to send the request
-```go
-director = func(ctx context.Context, fullMethodName string) (*grpc.ClientConn, error) {
- // Make sure we never forward internal services.
- if strings.HasPrefix(fullMethodName, "/com.example.internal.") {
- return nil, grpc.Errorf(codes.Unimplemented, "Unknown method")
- }
- md, ok := metadata.FromContext(ctx)
- if ok {
- // Decide on which backend to dial
- if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" {
- // Make sure we use DialContext so the dialing can be cancelled/time out together with the context.
- return grpc.DialContext(ctx, "api-service.staging.svc.local", grpc.WithCodec(proxy.NewCodec()))
- } else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" {
- return grpc.DialContext(ctx, "api-service.prod.svc.local", grpc.WithCodec(proxy.NewCodec()))
- }
- }
- return nil, grpc.Errorf(codes.Unimplemented, "Unknown method")
-}
-```
-Then you need to register it with a `grpc.Server`. The server may have other handlers that will be served
-locally:
-
-```go
-server := grpc.NewServer(
- grpc.CustomCodec(proxy.NewCodec()),
- grpc.UnknownServiceHandler(proxy.TransparentHandler(director)))
-pb_test.RegisterTestServiceServer(server, &testImpl{})
-```
-
-## License
-
-`grpc-proxy` is released under the Apache 2.0 license. See [LICENSE.txt](LICENSE.txt).
-
diff --git a/internal/praefect/grpc-proxy/checkup.sh b/internal/praefect/grpc-proxy/checkup.sh
deleted file mode 100755
index 37e9aac6e..000000000
--- a/internal/praefect/grpc-proxy/checkup.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-# Script that checks up code (govet).
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
-
-function print_real_go_files {
- grep --files-without-match 'DO NOT EDIT!' $(find . -iname '*.go')
-}
-
-function govet_all {
- ret=0
- for i in $(print_real_go_files); do
- output=$(go tool vet -all=true -tests=false ${i})
- ret=$(($ret | $?))
- echo -n ${output}
- done;
- return ${ret}
-}
-
-govet_all
-echo "returning $?" \ No newline at end of file
diff --git a/internal/praefect/grpc-proxy/fixup.sh b/internal/praefect/grpc-proxy/fixup.sh
deleted file mode 100755
index 5b4a66ade..000000000
--- a/internal/praefect/grpc-proxy/fixup.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# Script that checks the code for errors.
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
-
-function print_real_go_files {
- grep --files-without-match 'DO NOT EDIT!' $(find . -iname '*.go')
-}
-
-function generate_markdown {
- echo "Generating markdown"
- oldpwd=$(pwd)
- for i in $(find . -iname 'doc.go'); do
- dir=${i%/*}
- echo "$dir"
- cd ${dir}
- ${GOPATH}/bin/godocdown -heading=Title -o DOC.md
- ln -s DOC.md README.md 2> /dev/null # can fail
- cd ${oldpwd}
- done;
-}
-
-function goimports_all {
- echo "Running goimports"
- goimports -l -w $(print_real_go_files)
- return $?
-}
-
-generate_markdown
-goimports_all
-echo "returning $?" \ No newline at end of file
diff --git a/internal/praefect/grpc-proxy/proxy/DOC.md b/internal/praefect/grpc-proxy/proxy/DOC.md
deleted file mode 100644
index 55fc8c810..000000000
--- a/internal/praefect/grpc-proxy/proxy/DOC.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# proxy
---
- import "github.com/mwitkow/grpc-proxy/proxy"
-
-Package proxy provides a reverse proxy handler for gRPC.
-
-The implementation allows a `grpc.Server` to pass a received ServerStream to a
-ClientStream without understanding the semantics of the messages exchanged. It
-basically provides a transparent reverse-proxy.
-
-This package is intentionally generic, exposing a `StreamDirector` function that
-allows users of this package to implement whatever logic of backend-picking,
-dialing and service verification to perform.
-
-See examples on documented functions.
-
-## Usage
-
-#### func Codec
-
-```go
-func NewCodec() Codec
-```
-Codec returns a proxying Codec with the default protobuf codec as parent.
-
-See CodecWithParent.
-
-#### func CodecWithParent
-
-```go
-func CodecWithParent(fallback grpc.Codec) Codec
-```
-CodecWithParent returns a proxying grpc.Codec with a user provided codec as
-parent.
-
-This codec is *crucial* to the functioning of the proxy. It allows the proxy
-server to be oblivious to the schema of the forwarded messages. It basically
-treats a gRPC message frame as raw bytes. However, if the server handler, or the
-client caller are not proxy-internal functions it will fall back to trying to
-decode the message using a fallback codec.
-
-#### func RegisterService
-
-```go
-func RegisterService(server *grpc.Server, director StreamDirector, serviceName string, methodNames ...string)
-```
-RegisterService sets up a proxy handler for a particular gRPC service and
-method. The behaviour is the same as if you were registering a handler method,
-e.g. from a codegenerated pb.go file.
-
-This can *only* be used if the `server` also uses grpcproxy.CodecForServer()
-ServerOption.
-
-#### func TransparentHandler
-
-```go
-func TransparentHandler(director StreamDirector) grpc.StreamHandler
-```
-TransparentHandler returns a handler that attempts to proxy all requests that
-are not registered in the server. The indented use here is as a transparent
-proxy, where the server doesn't know about the services implemented by the
-backends. It should be used as a `grpc.UnknownServiceHandler`.
-
-This can *only* be used if the `server` also uses grpcproxy.CodecForServer()
-ServerOption.
-
-#### type StreamDirector
-
-```go
-type StreamDirector func(ctx context.Context, fullMethodName string) (*grpc.ClientConn, error)
-```
-
-StreamDirector returns a gRPC ClientConn to be used to forward the call to.
-
-The presence of the `Context` allows for rich filtering, e.g. based on Metadata
-(headers). If no handling is meant to be done, a `codes.NotImplemented` gRPC
-error should be returned.
-
-It is worth noting that the StreamDirector will be fired *after* all server-side
-stream interceptors are invoked. So decisions around authorization, monitoring
-etc. are better to be handled there.
-
-See the rather rich example.
diff --git a/internal/praefect/grpc-proxy/proxy/README.md b/internal/praefect/grpc-proxy/proxy/README.md
deleted file mode 120000
index 71bfc07c9..000000000
--- a/internal/praefect/grpc-proxy/proxy/README.md
+++ /dev/null
@@ -1 +0,0 @@
-DOC.md \ No newline at end of file
diff --git a/internal/praefect/grpc-proxy/proxy/examples_test.go b/internal/praefect/grpc-proxy/proxy/examples_test.go
deleted file mode 100644
index 7de70230f..000000000
--- a/internal/praefect/grpc-proxy/proxy/examples_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 Michal Witkowski. All Rights Reserved.
-// See LICENSE for licensing terms.
-
-package proxy_test
-
-import (
- "context"
- "strings"
-
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
- "google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- grpc_metadata "google.golang.org/grpc/metadata"
- "google.golang.org/grpc/status"
-)
-
-var director proxy.StreamDirector
-
-func ExampleRegisterService() {
- // A gRPC server with the proxying codec enabled.
- server := grpc.NewServer(grpc.ForceServerCodec(proxy.NewCodec()))
- // Register a TestService with 4 of its methods explicitly.
- proxy.RegisterService(server, director,
- "mwitkow.testproto.TestService",
- "PingEmpty", "Ping", "PingError", "PingList")
-}
-
-func ExampleTransparentHandler() {
- grpc.NewServer(
- grpc.ForceServerCodec(proxy.NewCodec()),
- grpc.UnknownServiceHandler(proxy.TransparentHandler(director)))
-}
-
-// Provide sa simple example of a director that shields internal services and dials a staging or production backend.
-// This is a *very naive* implementation that creates a new connection on every request. Consider using pooling.
-func ExampleStreamDirector() {
- director = func(ctx context.Context, fullMethodName string, _ proxy.StreamPeeker) (*proxy.StreamParameters, error) {
- // Make sure we never forward internal services.
- if strings.HasPrefix(fullMethodName, "/com.example.internal.") {
- return nil, status.Errorf(codes.Unimplemented, "Unknown method")
- }
- md, ok := grpc_metadata.FromIncomingContext(ctx)
- if ok {
- // Decide on which backend to dial
- if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" {
- // Make sure we use DialContext so the dialing can be cancelled/time out together with the context.
- conn, err := grpc.DialContext(ctx, "api-service.staging.svc.local", grpc.WithDefaultCallOptions(grpc.ForceCodec(proxy.NewCodec())))
- return proxy.NewStreamParameters(proxy.Destination{
- Conn: conn,
- Ctx: metadata.IncomingToOutgoing(ctx),
- }, nil, nil, nil), err
- } else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" {
- conn, err := grpc.DialContext(ctx, "api-service.prod.svc.local", grpc.WithDefaultCallOptions(grpc.ForceCodec(proxy.NewCodec())))
- return proxy.NewStreamParameters(proxy.Destination{
- Conn: conn,
- Ctx: metadata.IncomingToOutgoing(ctx),
- }, nil, nil, nil), err
- }
- }
- return nil, status.Errorf(codes.Unimplemented, "Unknown method")
- }
-}
diff --git a/internal/praefect/info_service_test.go b/internal/praefect/info_service_test.go
index 334b294ab..e1f989149 100644
--- a/internal/praefect/info_service_test.go
+++ b/internal/praefect/info_service_test.go
@@ -7,18 +7,18 @@ import (
"testing"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
gconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/repository"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/transactions"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testdb"
diff --git a/internal/praefect/middleware/errorhandler_test.go b/internal/praefect/middleware/errorhandler_test.go
index da157cca1..18e689ecf 100644
--- a/internal/praefect/middleware/errorhandler_test.go
+++ b/internal/praefect/middleware/errorhandler_test.go
@@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes/tracker"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
diff --git a/internal/praefect/node.go b/internal/praefect/node.go
index a4b9ec688..0f5785918 100644
--- a/internal/praefect/node.go
+++ b/internal/praefect/node.go
@@ -5,11 +5,11 @@ import (
"fmt"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes/tracker"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"google.golang.org/grpc"
"google.golang.org/grpc/health/grpc_health_v1"
)
diff --git a/internal/praefect/nodes/manager.go b/internal/praefect/nodes/manager.go
index 876d5bb5a..ab8fb5fe6 100644
--- a/internal/praefect/nodes/manager.go
+++ b/internal/praefect/nodes/manager.go
@@ -14,16 +14,16 @@ import (
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
"gitlab.com/gitlab-org/gitaly/v16/internal/datastructure"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/client"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/metrics"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/middleware"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes/tracker"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
prommetrics "gitlab.com/gitlab-org/gitaly/v16/internal/prometheus/metrics"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
diff --git a/internal/praefect/nodes/sql_elector_test.go b/internal/praefect/nodes/sql_elector_test.go
index 047c0cb6d..65fa7271e 100644
--- a/internal/praefect/nodes/sql_elector_test.go
+++ b/internal/praefect/nodes/sql_elector_test.go
@@ -11,8 +11,8 @@ import (
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore/glsql"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
diff --git a/internal/praefect/reconciler/reconciler_test.go b/internal/praefect/reconciler/reconciler_test.go
index 66ae97307..bf68e4898 100644
--- a/internal/praefect/reconciler/reconciler_test.go
+++ b/internal/praefect/reconciler/reconciler_test.go
@@ -9,8 +9,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
diff --git a/internal/praefect/remove_all_test.go b/internal/praefect/remove_all_test.go
index ecec560d7..58686559b 100644
--- a/internal/praefect/remove_all_test.go
+++ b/internal/praefect/remove_all_test.go
@@ -9,9 +9,9 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/praefect/remove_repository_test.go b/internal/praefect/remove_repository_test.go
index d5dc7d917..fb91f2efc 100644
--- a/internal/praefect/remove_repository_test.go
+++ b/internal/praefect/remove_repository_test.go
@@ -11,9 +11,9 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/praefect/replicator.go b/internal/praefect/replicator.go
index bbbf69269..841871741 100644
--- a/internal/praefect/replicator.go
+++ b/internal/praefect/replicator.go
@@ -11,8 +11,8 @@ import (
"github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
prommetrics "gitlab.com/gitlab-org/gitaly/v16/internal/prometheus/metrics"
diff --git a/internal/praefect/replicator_test.go b/internal/praefect/replicator_test.go
index 288937e0a..3114e3d05 100644
--- a/internal/praefect/replicator_test.go
+++ b/internal/praefect/replicator_test.go
@@ -20,8 +20,8 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
diff --git a/internal/praefect/repocleaner/repository_test.go b/internal/praefect/repocleaner/repository_test.go
index fef4cbf69..4cd415900 100644
--- a/internal/praefect/repocleaner/repository_test.go
+++ b/internal/praefect/repocleaner/repository_test.go
@@ -13,9 +13,9 @@ import (
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
diff --git a/internal/praefect/repository_exists_test.go b/internal/praefect/repository_exists_test.go
index 9106d85a2..84f4df527 100644
--- a/internal/praefect/repository_exists_test.go
+++ b/internal/praefect/repository_exists_test.go
@@ -7,9 +7,9 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
diff --git a/internal/praefect/router_per_repository.go b/internal/praefect/router_per_repository.go
index 59cdbcff1..63070ecfb 100644
--- a/internal/praefect/router_per_repository.go
+++ b/internal/praefect/router_per_repository.go
@@ -5,8 +5,8 @@ import (
"errors"
"fmt"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/stats"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/praefectutil"
diff --git a/internal/praefect/router_per_repository_test.go b/internal/praefect/router_per_repository_test.go
index b6396c9b0..e4c032aa9 100644
--- a/internal/praefect/router_per_repository_test.go
+++ b/internal/praefect/router_per_repository_test.go
@@ -7,8 +7,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/commonerr"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
diff --git a/internal/praefect/server.go b/internal/praefect/server.go
index 3be311a8c..0b5696a97 100644
--- a/internal/praefect/server.go
+++ b/internal/praefect/server.go
@@ -11,18 +11,19 @@ import (
grpcmwtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/sirupsen/logrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/server/auth"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/metadatahandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/panichandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/sentryhandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/statushandler"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/fieldextractors"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/metadatahandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/panichandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/sentryhandler"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/statushandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/middleware"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service"
@@ -30,7 +31,6 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/server"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/transactions"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc"
grpctracing "gitlab.com/gitlab-org/labkit/tracing/grpc"
diff --git a/internal/praefect/server_factory.go b/internal/praefect/server_factory.go
index 55ca84de7..637be14ff 100644
--- a/internal/praefect/server_factory.go
+++ b/internal/praefect/server_factory.go
@@ -7,9 +7,9 @@ import (
"sync"
"github.com/sirupsen/logrus"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service"
diff --git a/internal/praefect/server_factory_test.go b/internal/praefect/server_factory_test.go
index c0614ae67..2a5641d9b 100644
--- a/internal/praefect/server_factory_test.go
+++ b/internal/praefect/server_factory_test.go
@@ -16,20 +16,20 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/bootstrap/starter"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
gconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/text"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/transactions"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/promtest"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
diff --git a/internal/praefect/server_test.go b/internal/praefect/server_test.go
index 2ff7e26f2..b9eb1544a 100644
--- a/internal/praefect/server_test.go
+++ b/internal/praefect/server_test.go
@@ -19,17 +19,17 @@ import (
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/datastructure"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
gconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
- "gitlab.com/gitlab-org/gitaly/v16/internal/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/listenmux"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes/tracker"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
diff --git a/internal/praefect/service/server/info.go b/internal/praefect/service/server/info.go
index 753b29ecf..9481ecb8d 100644
--- a/internal/praefect/service/server/info.go
+++ b/internal/praefect/service/server/info.go
@@ -6,7 +6,7 @@ import (
"github.com/google/uuid"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/metadata"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc"
)
diff --git a/internal/praefect/testserver.go b/internal/praefect/testserver.go
index ace4e9f36..ddfd7bb90 100644
--- a/internal/praefect/testserver.go
+++ b/internal/praefect/testserver.go
@@ -12,10 +12,10 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/client"
gitalycfgauth "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/auth"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/server/auth"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/log"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
- "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/grpc-proxy/proxy"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service"
diff --git a/internal/praefect/verifier_test.go b/internal/praefect/verifier_test.go
index eaed7d039..f7938c34a 100644
--- a/internal/praefect/verifier_test.go
+++ b/internal/praefect/verifier_test.go
@@ -13,12 +13,13 @@ import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
gitalyconfig "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/repository"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service/setup"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/datastore"
@@ -27,7 +28,6 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/protoregistry"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/service/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/praefect/transactions"
- "gitlab.com/gitlab-org/gitaly/v16/internal/sidechannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
"gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testdb"
diff --git a/internal/testhelper/featureset.go b/internal/testhelper/featureset.go
index f6bbb08fa..54ad33ba7 100644
--- a/internal/testhelper/featureset.go
+++ b/internal/testhelper/featureset.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
)
// FeatureSet is a representation of a set of features that should be disabled.
diff --git a/internal/testhelper/featureset_test.go b/internal/testhelper/featureset_test.go
index 71a0dc7f7..956345adc 100644
--- a/internal/testhelper/featureset_test.go
+++ b/internal/testhelper/featureset_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
- ff "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
+ ff "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"google.golang.org/grpc/metadata"
)
diff --git a/internal/testhelper/leakage.go b/internal/testhelper/leakage.go
index c0bfcb4a2..5fa5a387b 100644
--- a/internal/testhelper/leakage.go
+++ b/internal/testhelper/leakage.go
@@ -29,7 +29,7 @@ func mustHaveNoGoroutines() {
goleak.IgnoreTopFunction("gitlab.com/gitlab-org/labkit/log.listenForSignalHangup"),
// The backchannel code is somehow stock on closing its connections. I have no clue
// why that is, but we should investigate.
- goleak.IgnoreTopFunction(PkgPath("internal/backchannel.clientHandshake.serve.func4")),
+ goleak.IgnoreTopFunction(PkgPath("internal/grpc/backchannel.clientHandshake.serve.func4")),
); err != nil {
panic(fmt.Errorf("goroutines running: %w", err))
}
diff --git a/internal/testhelper/testhelper.go b/internal/testhelper/testhelper.go
index 642b4aea7..327288a56 100644
--- a/internal/testhelper/testhelper.go
+++ b/internal/testhelper/testhelper.go
@@ -28,8 +28,8 @@ import (
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/featureflag"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/metadata/featureflag"
"golang.org/x/exp/slices"
)
diff --git a/internal/testhelper/testserver/gitaly.go b/internal/testhelper/testserver/gitaly.go
index b9a62e363..0f7349d7c 100644
--- a/internal/testhelper/testserver/gitaly.go
+++ b/internal/testhelper/testserver/gitaly.go
@@ -11,7 +11,6 @@ import (
"github.com/stretchr/testify/require"
gitalyauth "gitlab.com/gitlab-org/gitaly/v16/auth"
"gitlab.com/gitlab-org/gitaly/v16/client"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
"gitlab.com/gitlab-org/gitaly/v16/internal/cache"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/catfile"
@@ -29,8 +28,9 @@ import (
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/transaction"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitlab"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/middleware/limithandler"
"gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
- "gitlab.com/gitlab-org/gitaly/v16/internal/middleware/limithandler"
praefectconfig "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/streamcache"
"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
diff --git a/internal/transaction/txinfo/transaction.go b/internal/transaction/txinfo/transaction.go
index ae0a2ce75..3f21bbd92 100644
--- a/internal/transaction/txinfo/transaction.go
+++ b/internal/transaction/txinfo/transaction.go
@@ -7,7 +7,7 @@ import (
"errors"
"fmt"
- "gitlab.com/gitlab-org/gitaly/v16/internal/backchannel"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/grpc/backchannel"
"google.golang.org/grpc/metadata"
)
diff --git a/proto/go/gitalypb/internal.pb.go b/proto/go/gitalypb/internal.pb.go
index 024bd48d4..abac28f7c 100644
--- a/proto/go/gitalypb/internal.pb.go
+++ b/proto/go/gitalypb/internal.pb.go
@@ -130,6 +130,165 @@ func (x *WalkReposResponse) GetModificationTime() *timestamppb.Timestamp {
return nil
}
+// BackupReposRequest contains request parameters for the BackupRepos RPC.
+type BackupReposRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // For each request stream there must be first a request with a header
+ // containing details about the backups to perform.
+ Header *BackupReposRequest_Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
+ // Repositories to have a backups triggered.
+ Repositories []*Repository `protobuf:"bytes,2,rep,name=repositories,proto3" json:"repositories,omitempty"`
+}
+
+func (x *BackupReposRequest) Reset() {
+ *x = BackupReposRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BackupReposRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupReposRequest) ProtoMessage() {}
+
+func (x *BackupReposRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupReposRequest.ProtoReflect.Descriptor instead.
+func (*BackupReposRequest) Descriptor() ([]byte, []int) {
+ return file_internal_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *BackupReposRequest) GetHeader() *BackupReposRequest_Header {
+ if x != nil {
+ return x.Header
+ }
+ return nil
+}
+
+func (x *BackupReposRequest) GetRepositories() []*Repository {
+ if x != nil {
+ return x.Repositories
+ }
+ return nil
+}
+
+// BackupReposResponse contains response parameters for the BackupRepos RPC.
+type BackupReposResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *BackupReposResponse) Reset() {
+ *x = BackupReposResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BackupReposResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupReposResponse) ProtoMessage() {}
+
+func (x *BackupReposResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupReposResponse.ProtoReflect.Descriptor instead.
+func (*BackupReposResponse) Descriptor() ([]byte, []int) {
+ return file_internal_proto_rawDescGZIP(), []int{3}
+}
+
+// Header contains information to create the backups and must be sent in the
+// first message.
+type BackupReposRequest_Header struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // BackupId determines which collective backup these repository backups will
+ // be part of. Must be sent in first message.
+ BackupId string `protobuf:"bytes,1,opt,name=backup_id,json=backupId,proto3" json:"backup_id,omitempty"`
+ // StorageUrl is the object-storage URL where the backups will be stored.
+ // See https://gocloud.dev/howto/blob/ and https://gocloud.dev/concepts/urls/
+ StorageUrl string `protobuf:"bytes,2,opt,name=storage_url,json=storageUrl,proto3" json:"storage_url,omitempty"`
+}
+
+func (x *BackupReposRequest_Header) Reset() {
+ *x = BackupReposRequest_Header{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BackupReposRequest_Header) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupReposRequest_Header) ProtoMessage() {}
+
+func (x *BackupReposRequest_Header) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupReposRequest_Header.ProtoReflect.Descriptor instead.
+func (*BackupReposRequest_Header) Descriptor() ([]byte, []int) {
+ return file_internal_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (x *BackupReposRequest_Header) GetBackupId() string {
+ if x != nil {
+ return x.BackupId
+ }
+ return ""
+}
+
+func (x *BackupReposRequest_Header) GetStorageUrl() string {
+ if x != nil {
+ return x.StorageUrl
+ }
+ return ""
+}
+
var File_internal_proto protoreflect.FileDescriptor
var file_internal_proto_rawDesc = []byte{
@@ -137,25 +296,46 @@ var file_internal_proto_rawDesc = []byte{
0x12, 0x06, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x6c, 0x69, 0x6e, 0x74, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3b, 0x0a, 0x10, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70,
- 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0c, 0x73, 0x74, 0x6f,
- 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
- 0x04, 0x88, 0xc6, 0x2c, 0x01, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61,
- 0x6d, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61,
- 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x47, 0x0a,
- 0x11, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69,
- 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
- 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x32, 0x5e, 0x0a, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x61, 0x6c, 0x47, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x12, 0x4c, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6b,
- 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57,
- 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
- 0x19, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70,
- 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xfa, 0x97, 0x28, 0x04,
- 0x08, 0x02, 0x10, 0x02, 0x30, 0x01, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x22, 0x3b, 0x0a, 0x10, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61,
+ 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x88,
+ 0xc6, 0x2c, 0x01, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+ 0x22, 0x81, 0x01, 0x0a, 0x11, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
+ 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72,
+ 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x47, 0x0a, 0x11, 0x6d,
+ 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x52, 0x10, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x54, 0x69, 0x6d, 0x65, 0x22, 0xd5, 0x01, 0x0a, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52,
+ 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x68,
+ 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x69,
+ 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6f, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06,
+ 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67,
+ 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
+ 0x42, 0x04, 0x98, 0xc6, 0x2c, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x65, 0x73, 0x1a, 0x46, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1b,
+ 0x0a, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x08, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73,
+ 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x15, 0x0a, 0x13,
+ 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x32, 0xb0, 0x01, 0x0a, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
+ 0x47, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x12, 0x4c, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65,
+ 0x70, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x61, 0x6c,
+ 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e,
+ 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xfa, 0x97, 0x28, 0x04, 0x08, 0x02,
+ 0x10, 0x02, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65,
+ 0x70, 0x6f, 0x73, 0x12, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x1b, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52,
+ 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97,
+ 0x28, 0x02, 0x08, 0x02, 0x28, 0x01, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f,
0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72,
@@ -174,21 +354,29 @@ func file_internal_proto_rawDescGZIP() []byte {
return file_internal_proto_rawDescData
}
-var file_internal_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_internal_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_internal_proto_goTypes = []interface{}{
- (*WalkReposRequest)(nil), // 0: gitaly.WalkReposRequest
- (*WalkReposResponse)(nil), // 1: gitaly.WalkReposResponse
- (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp
+ (*WalkReposRequest)(nil), // 0: gitaly.WalkReposRequest
+ (*WalkReposResponse)(nil), // 1: gitaly.WalkReposResponse
+ (*BackupReposRequest)(nil), // 2: gitaly.BackupReposRequest
+ (*BackupReposResponse)(nil), // 3: gitaly.BackupReposResponse
+ (*BackupReposRequest_Header)(nil), // 4: gitaly.BackupReposRequest.Header
+ (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp
+ (*Repository)(nil), // 6: gitaly.Repository
}
var file_internal_proto_depIdxs = []int32{
- 2, // 0: gitaly.WalkReposResponse.modification_time:type_name -> google.protobuf.Timestamp
- 0, // 1: gitaly.InternalGitaly.WalkRepos:input_type -> gitaly.WalkReposRequest
- 1, // 2: gitaly.InternalGitaly.WalkRepos:output_type -> gitaly.WalkReposResponse
- 2, // [2:3] is the sub-list for method output_type
- 1, // [1:2] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
+ 5, // 0: gitaly.WalkReposResponse.modification_time:type_name -> google.protobuf.Timestamp
+ 4, // 1: gitaly.BackupReposRequest.header:type_name -> gitaly.BackupReposRequest.Header
+ 6, // 2: gitaly.BackupReposRequest.repositories:type_name -> gitaly.Repository
+ 0, // 3: gitaly.InternalGitaly.WalkRepos:input_type -> gitaly.WalkReposRequest
+ 2, // 4: gitaly.InternalGitaly.BackupRepos:input_type -> gitaly.BackupReposRequest
+ 1, // 5: gitaly.InternalGitaly.WalkRepos:output_type -> gitaly.WalkReposResponse
+ 3, // 6: gitaly.InternalGitaly.BackupRepos:output_type -> gitaly.BackupReposResponse
+ 5, // [5:7] is the sub-list for method output_type
+ 3, // [3:5] is the sub-list for method input_type
+ 3, // [3:3] is the sub-list for extension type_name
+ 3, // [3:3] is the sub-list for extension extendee
+ 0, // [0:3] is the sub-list for field type_name
}
func init() { file_internal_proto_init() }
@@ -197,6 +385,7 @@ func file_internal_proto_init() {
return
}
file_lint_proto_init()
+ file_shared_proto_init()
if !protoimpl.UnsafeEnabled {
file_internal_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WalkReposRequest); i {
@@ -222,6 +411,42 @@ func file_internal_proto_init() {
return nil
}
}
+ file_internal_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BackupReposRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_internal_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BackupReposResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_internal_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BackupReposRequest_Header); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -229,7 +454,7 @@ func file_internal_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_internal_proto_rawDesc,
NumEnums: 0,
- NumMessages: 2,
+ NumMessages: 5,
NumExtensions: 0,
NumServices: 1,
},
diff --git a/proto/go/gitalypb/internal_grpc.pb.go b/proto/go/gitalypb/internal_grpc.pb.go
index 3ff76c214..ca1784197 100644
--- a/proto/go/gitalypb/internal_grpc.pb.go
+++ b/proto/go/gitalypb/internal_grpc.pb.go
@@ -25,6 +25,9 @@ type InternalGitalyClient interface {
// WalkRepos walks the storage and streams back all known git repos on the
// requested storage
WalkRepos(ctx context.Context, in *WalkReposRequest, opts ...grpc.CallOption) (InternalGitaly_WalkReposClient, error)
+ // BackupRepos triggers a backup for each repository in the stream. This RPC
+ // is intended to be used to coordinate backups within the gitaly cluster.
+ BackupRepos(ctx context.Context, opts ...grpc.CallOption) (InternalGitaly_BackupReposClient, error)
}
type internalGitalyClient struct {
@@ -67,6 +70,40 @@ func (x *internalGitalyWalkReposClient) Recv() (*WalkReposResponse, error) {
return m, nil
}
+func (c *internalGitalyClient) BackupRepos(ctx context.Context, opts ...grpc.CallOption) (InternalGitaly_BackupReposClient, error) {
+ stream, err := c.cc.NewStream(ctx, &InternalGitaly_ServiceDesc.Streams[1], "/gitaly.InternalGitaly/BackupRepos", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &internalGitalyBackupReposClient{stream}
+ return x, nil
+}
+
+type InternalGitaly_BackupReposClient interface {
+ Send(*BackupReposRequest) error
+ CloseAndRecv() (*BackupReposResponse, error)
+ grpc.ClientStream
+}
+
+type internalGitalyBackupReposClient struct {
+ grpc.ClientStream
+}
+
+func (x *internalGitalyBackupReposClient) Send(m *BackupReposRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *internalGitalyBackupReposClient) CloseAndRecv() (*BackupReposResponse, error) {
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ m := new(BackupReposResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
// InternalGitalyServer is the server API for InternalGitaly service.
// All implementations must embed UnimplementedInternalGitalyServer
// for forward compatibility
@@ -74,6 +111,9 @@ type InternalGitalyServer interface {
// WalkRepos walks the storage and streams back all known git repos on the
// requested storage
WalkRepos(*WalkReposRequest, InternalGitaly_WalkReposServer) error
+ // BackupRepos triggers a backup for each repository in the stream. This RPC
+ // is intended to be used to coordinate backups within the gitaly cluster.
+ BackupRepos(InternalGitaly_BackupReposServer) error
mustEmbedUnimplementedInternalGitalyServer()
}
@@ -84,6 +124,9 @@ type UnimplementedInternalGitalyServer struct {
func (UnimplementedInternalGitalyServer) WalkRepos(*WalkReposRequest, InternalGitaly_WalkReposServer) error {
return status.Errorf(codes.Unimplemented, "method WalkRepos not implemented")
}
+func (UnimplementedInternalGitalyServer) BackupRepos(InternalGitaly_BackupReposServer) error {
+ return status.Errorf(codes.Unimplemented, "method BackupRepos not implemented")
+}
func (UnimplementedInternalGitalyServer) mustEmbedUnimplementedInternalGitalyServer() {}
// UnsafeInternalGitalyServer may be embedded to opt out of forward compatibility for this service.
@@ -118,6 +161,32 @@ func (x *internalGitalyWalkReposServer) Send(m *WalkReposResponse) error {
return x.ServerStream.SendMsg(m)
}
+func _InternalGitaly_BackupRepos_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(InternalGitalyServer).BackupRepos(&internalGitalyBackupReposServer{stream})
+}
+
+type InternalGitaly_BackupReposServer interface {
+ SendAndClose(*BackupReposResponse) error
+ Recv() (*BackupReposRequest, error)
+ grpc.ServerStream
+}
+
+type internalGitalyBackupReposServer struct {
+ grpc.ServerStream
+}
+
+func (x *internalGitalyBackupReposServer) SendAndClose(m *BackupReposResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *internalGitalyBackupReposServer) Recv() (*BackupReposRequest, error) {
+ m := new(BackupReposRequest)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
// InternalGitaly_ServiceDesc is the grpc.ServiceDesc for InternalGitaly service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -131,6 +200,11 @@ var InternalGitaly_ServiceDesc = grpc.ServiceDesc{
Handler: _InternalGitaly_WalkRepos_Handler,
ServerStreams: true,
},
+ {
+ StreamName: "BackupRepos",
+ Handler: _InternalGitaly_BackupRepos_Handler,
+ ClientStreams: true,
+ },
},
Metadata: "internal.proto",
}
diff --git a/proto/go/gitalypb/testproto/error_metadata.pb.go b/proto/go/gitalypb/testproto/error_metadata.pb.go
index 74caf99b1..b45c2ccfd 100644
--- a/proto/go/gitalypb/testproto/error_metadata.pb.go
+++ b/proto/go/gitalypb/testproto/error_metadata.pb.go
@@ -89,10 +89,11 @@ var file_testproto_error_metadata_proto_rawDesc = []byte{
0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63,
+ 0x61, 0x6c, 0x75, 0x65, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69,
- 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74,
- 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67,
+ 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/proto/go/gitalypb/testproto/invalid.pb.go b/proto/go/gitalypb/testproto/invalid.pb.go
index 299b75ce7..ec3de26a4 100644
--- a/proto/go/gitalypb/testproto/invalid.pb.go
+++ b/proto/go/gitalypb/testproto/invalid.pb.go
@@ -976,10 +976,11 @@ var file_testproto_invalid_proto_rawDesc = []byte{
0x52, 0x65, 0x70, 0x6f, 0x1a, 0x20, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xfa, 0x97, 0x28, 0x04, 0x08, 0x03, 0x10, 0x02,
- 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67,
+ 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67,
0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79,
- 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x69,
+ 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/proto/go/gitalypb/testproto/valid.pb.go b/proto/go/gitalypb/testproto/valid.pb.go
index 60d0ec725..50eb1021a 100644
--- a/proto/go/gitalypb/testproto/valid.pb.go
+++ b/proto/go/gitalypb/testproto/valid.pb.go
@@ -659,10 +659,11 @@ var file_testproto_valid_proto_rawDesc = []byte{
0x6e, 0x6e, 0x65, 0x72, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x61,
0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xfa, 0x97, 0x28,
- 0x02, 0x08, 0x03, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f,
+ 0x02, 0x08, 0x03, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74,
- 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x65,
- 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f,
+ 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/proto/internal.proto b/proto/internal.proto
index 44f18d609..1e3f40882 100644
--- a/proto/internal.proto
+++ b/proto/internal.proto
@@ -4,6 +4,7 @@ package gitaly;
import "google/protobuf/timestamp.proto";
import "lint.proto";
+import "shared.proto";
option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb";
@@ -18,6 +19,14 @@ service InternalGitaly {
scope_level: STORAGE
};
}
+
+ // BackupRepos triggers a backup for each repository in the stream. This RPC
+ // is intended to be used to coordinate backups within the gitaly cluster.
+ rpc BackupRepos (stream BackupReposRequest) returns (BackupReposResponse) {
+ option (op_type) = {
+ op: ACCESSOR
+ };
+ }
}
// This comment is left unintentionally blank.
@@ -35,3 +44,29 @@ message WalkReposResponse {
// modified.
google.protobuf.Timestamp modification_time = 2;
}
+
+// BackupReposRequest contains request parameters for the BackupRepos RPC.
+message BackupReposRequest {
+ // Header contains information to create the backups and must be sent in the
+ // first message.
+ message Header {
+ // BackupId determines which collective backup these repository backups will
+ // be part of. Must be sent in first message.
+ string backup_id = 1;
+
+ // StorageUrl is the object-storage URL where the backups will be stored.
+ // See https://gocloud.dev/howto/blob/ and https://gocloud.dev/concepts/urls/
+ string storage_url = 2;
+ }
+
+ // For each request stream there must be first a request with a header
+ // containing details about the backups to perform.
+ Header header = 1;
+
+ // Repositories to have a backups triggered.
+ repeated Repository repositories = 2 [(target_repository)=true];
+}
+
+// BackupReposResponse contains response parameters for the BackupRepos RPC.
+message BackupReposResponse {
+}
diff --git a/proto/testproto/error_metadata.proto b/proto/testproto/error_metadata.proto
index d0ddcd86f..325ccc8ca 100644
--- a/proto/testproto/error_metadata.proto
+++ b/proto/testproto/error_metadata.proto
@@ -2,7 +2,7 @@ syntax = "proto3";
package testproto;
-option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/testproto";
+option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb/testproto";
// ErrorMetadata is a key-value metadata item that may be attached to errors. We only use this
// infrastructure for testing purposes to assert that we add error metadata as expected that would
diff --git a/proto/testproto/invalid.proto b/proto/testproto/invalid.proto
index ffa0ca3d2..33db4d2fb 100644
--- a/proto/testproto/invalid.proto
+++ b/proto/testproto/invalid.proto
@@ -5,7 +5,7 @@ package testproto;
import "lint.proto";
import "shared.proto";
-option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/testproto";
+option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb/testproto";
message InvalidMethodRequest {
}
diff --git a/proto/testproto/valid.proto b/proto/testproto/valid.proto
index 2d009ded4..82a51e924 100644
--- a/proto/testproto/valid.proto
+++ b/proto/testproto/valid.proto
@@ -5,7 +5,7 @@ package testproto;
import "lint.proto";
import "shared.proto";
-option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/testproto";
+option go_package = "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb/testproto";
message ValidRequest {
gitaly.Repository destination = 1 [(gitaly.target_repository)=true];