Commit 36c15356 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch '216174-track-mr-usage' into 'master'

Track merge_requests_users usage data

See merge request gitlab-org/gitlab!32562
parents 88e4e3c2 f1bfb5fd
---
title: Track merge_requests_users usage data
merge_request: 32562
author:
type: changed
......@@ -4,14 +4,15 @@ class AddIndexOnAuthorIdAndCreatedAtToEvents < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_events_on_author_id_and_created_at'
disable_ddl_transaction!
def up
add_concurrent_index :events, [:author_id, :created_at]
add_concurrent_index :events, [:author_id, :created_at], name: INDEX_NAME
end
def down
remove_concurrent_index :events, [:author_id, :created_at]
remove_concurrent_index :events, INDEX_NAME
end
end
# frozen_string_literal: true
class AddMergeRequestPartialIndexToEvents < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME = 'index_events_on_author_id_and_created_at_merge_requests'
def up
add_concurrent_index(
:events,
[:author_id, :created_at],
name: INDEX_NAME,
where: "(target_type = 'MergeRequest')"
)
end
def down
remove_concurrent_index :events, INDEX_NAME
end
end
......@@ -9708,6 +9708,8 @@ CREATE INDEX index_events_on_action ON public.events USING btree (action);
CREATE INDEX index_events_on_author_id_and_created_at ON public.events USING btree (author_id, created_at);
CREATE INDEX index_events_on_author_id_and_created_at_merge_requests ON public.events USING btree (author_id, created_at) WHERE ((target_type)::text = 'MergeRequest'::text);
CREATE INDEX index_events_on_author_id_and_project_id ON public.events USING btree (author_id, project_id);
CREATE INDEX index_events_on_group_id_partial ON public.events USING btree (group_id) WHERE (group_id IS NOT NULL);
......@@ -14048,5 +14050,6 @@ COPY "schema_migrations" (version) FROM STDIN;
20200527151413
20200527152116
20200527152657
20200528123703
\.
......@@ -39,8 +39,8 @@ module EE
override :uncached_data
def uncached_data
time_period = { created_at: 28.days.ago..Time.current }
usage_activity_by_stage_monthly = usage_activity_by_stage(:usage_activity_by_stage_monthly, time_period)
usage_activity_by_stage_monthly = usage_activity_by_stage(:usage_activity_by_stage_monthly, default_time_period)
super
.merge(usage_activity_by_stage)
.merge(usage_activity_by_stage_monthly)
......
......@@ -32,6 +32,7 @@ module Gitlab
.merge(cycle_analytics_usage_data)
.merge(object_store_usage_data)
.merge(recording_ce_finish_data)
.merge(merge_requests_usage_data(default_time_period))
end
def to_json(force_refresh: false)
......@@ -385,6 +386,27 @@ module Gitlab
{} # augmented in EE
end
# rubocop: disable CodeReuse/ActiveRecord
def merge_requests_usage_data(time_period)
query =
Event
.where(target_type: Event::TARGET_TYPES[:merge_request].to_s)
.where(time_period)
merge_request_users = distinct_count(
query,
:author_id,
batch_size: 5_000, # Based on query performance, this is the optimal batch size.
start: User.minimum(:id),
finish: User.maximum(:id)
)
{
merge_requests_users: merge_request_users
}
end
# rubocop: enable CodeReuse/ActiveRecord
def installation_type
if Rails.env.production?
Gitlab::INSTALLATION_TYPE
......@@ -392,6 +414,10 @@ module Gitlab
"gitlab-development-kit"
end
end
def default_time_period
{ created_at: 28.days.ago..Time.current }
end
end
end
end
......
......@@ -49,9 +49,9 @@ module Gitlab
FALLBACK
end
def distinct_count(relation, column = nil, batch: true, start: nil, finish: nil)
def distinct_count(relation, column = nil, batch: true, batch_size: nil, start: nil, finish: nil)
if batch && Feature.enabled?(:usage_ping_batch_counter, default_enabled: true)
Gitlab::Database::BatchCount.batch_distinct_count(relation, column, start: start, finish: finish)
Gitlab::Database::BatchCount.batch_distinct_count(relation, column, batch_size: batch_size, start: start, finish: finish)
else
relation.distinct_count_by(column)
end
......
......@@ -575,4 +575,27 @@ describe Gitlab::UsageData, :aggregate_failures do
it_behaves_like 'usage data execution'
end
describe '#merge_requests_usage_data' do
let(:time_period) { { created_at: 2.days.ago..Time.current } }
let(:merge_request) { create(:merge_request) }
let(:other_user) { create(:user) }
let(:another_user) { create(:user) }
before do
create(:event, target: merge_request, author: merge_request.author, created_at: 1.day.ago)
create(:event, target: merge_request, author: merge_request.author, created_at: 1.hour.ago)
create(:event, target: merge_request, author: merge_request.author, created_at: 3.days.ago)
create(:event, target: merge_request, author: other_user, created_at: 1.day.ago)
create(:event, target: merge_request, author: other_user, created_at: 1.hour.ago)
create(:event, target: merge_request, author: other_user, created_at: 3.days.ago)
create(:event, target: merge_request, author: another_user, created_at: 4.days.ago)
end
it 'returns the distinct count of users using merge requests (via events table) within the specified time period' do
expect(described_class.merge_requests_usage_data(time_period)).to eq(
merge_requests_users: 2
)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment