Commit 44fe828e authored by Matija Čupić's avatar Matija Čupić

Optimize #latest_successful_for_refs method

Optimizes Ci::Pipeline#latest_successful_for_refs to load just the
needed branches in two queries. Instead of loading all branches in one
query then filtering the needed branches in memory.

Changelog: fixed
parent 46982343
......@@ -377,11 +377,15 @@ module Ci
end
def self.latest_successful_for_refs(refs)
relation = newest_first(ref: refs).success
return Ci::Pipeline.none if refs.empty?
relation.each_with_object({}) do |pipeline, hash|
hash[pipeline.ref] ||= pipeline
end
refs_values = refs.map { |ref| "(#{connection.quote(ref)})" }.join(",")
join_query = success.where("refs_values.ref = ci_pipelines.ref").order(id: :desc).limit(1)
Ci::Pipeline
.from("(VALUES #{refs_values}) refs_values (ref)")
.joins("INNER JOIN LATERAL (#{join_query.to_sql}) #{Ci::Pipeline.table_name} ON TRUE")
.index_by(&:ref)
end
def self.latest_running_for_ref(ref)
......
......@@ -2263,18 +2263,38 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '.latest_successful_for_refs' do
let!(:latest_successful_pipeline1) do
create_pipeline(:success, 'ref1', 'D')
subject(:latest_successful_for_refs) { described_class.latest_successful_for_refs(refs) }
context 'when refs are specified' do
let(:refs) { %w(first_ref second_ref third_ref) }
before do
create(:ci_empty_pipeline, id: 1001, status: :success, ref: 'first_ref', sha: 'sha')
create(:ci_empty_pipeline, id: 1002, status: :success, ref: 'second_ref', sha: 'sha')
end
let!(:latest_successful_pipeline_for_first_ref) do
create(:ci_empty_pipeline, id: 2001, status: :success, ref: 'first_ref', sha: 'sha')
end
let!(:latest_successful_pipeline2) do
create_pipeline(:success, 'ref2', 'D')
let!(:latest_successful_pipeline_for_second_ref) do
create(:ci_empty_pipeline, id: 2002, status: :success, ref: 'second_ref', sha: 'sha')
end
it 'returns the latest successful pipeline for both refs' do
refs = %w(ref1 ref2 ref3)
expect(latest_successful_for_refs).to eq({
'first_ref' => latest_successful_pipeline_for_first_ref,
'second_ref' => latest_successful_pipeline_for_second_ref
})
end
end
expect(described_class.latest_successful_for_refs(refs)).to eq({ 'ref1' => latest_successful_pipeline1, 'ref2' => latest_successful_pipeline2 })
context 'when no refs are specified' do
let(:refs) { [] }
it 'returns an empty relation whenno refs are specified' do
expect(latest_successful_for_refs).to be_empty
end
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