gitlab-ce/spec/lib/gitlab/database/background_migration/batch_optimizer_spec.rb

127 lines
3.8 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::BackgroundMigration::BatchOptimizer do
describe '#optimize' do
subject { described_class.new(migration, number_of_jobs: number_of_jobs, ema_alpha: ema_alpha).optimize! }
let(:migration_params) { {} }
let(:migration) do
params = { batch_size: batch_size, sub_batch_size: 100, interval: 120 }.merge(migration_params)
create(:batched_background_migration, params)
end
let(:batch_size) { 10_000 }
let_it_be(:number_of_jobs) { 5 }
let_it_be(:ema_alpha) { 0.4 }
let_it_be(:target_efficiency) { described_class::TARGET_EFFICIENCY.max }
def mock_efficiency(eff)
expect(migration).to receive(:smoothed_time_efficiency).with(number_of_jobs: number_of_jobs, alpha: ema_alpha).and_return(eff)
end
it 'with unknown time efficiency, it keeps the batch size' do
mock_efficiency(nil)
expect { subject }.not_to change { migration.reload.batch_size }
end
it 'with a time efficiency of 95%, it keeps the batch size' do
mock_efficiency(0.95)
expect { subject }.not_to change { migration.reload.batch_size }
end
it 'with a time efficiency of 90%, it keeps the batch size' do
mock_efficiency(0.9)
expect { subject }.not_to change { migration.reload.batch_size }
end
it 'with a time efficiency of 85%, it increases the batch size' do
time_efficiency = 0.85
mock_efficiency(time_efficiency)
new_batch_size = ((target_efficiency / time_efficiency) * batch_size).to_i
expect { subject }.to change { migration.reload.batch_size }.from(batch_size).to(new_batch_size)
end
it 'with a time efficiency of 110%, it decreases the batch size' do
time_efficiency = 1.1
mock_efficiency(time_efficiency)
new_batch_size = ((target_efficiency / time_efficiency) * batch_size).to_i
expect { subject }.to change { migration.reload.batch_size }.from(batch_size).to(new_batch_size)
end
context 'reaching the upper limit for an increase' do
it 'caps the batch size multiplier at 20% when increasing' do
time_efficiency = 0.1 # this would result in a factor of 10 if not limited
mock_efficiency(time_efficiency)
new_batch_size = (1.2 * batch_size).to_i
expect { subject }.to change { migration.reload.batch_size }.from(batch_size).to(new_batch_size)
end
it 'does not limit the decrease multiplier' do
time_efficiency = 10
mock_efficiency(time_efficiency)
new_batch_size = (0.1 * batch_size).to_i
expect { subject }.to change { migration.reload.batch_size }.from(batch_size).to(new_batch_size)
end
end
context 'reaching the upper limit for the batch size' do
let(:batch_size) { 1_950_000 }
it 'caps the batch size at 10M' do
mock_efficiency(0.7)
expect { subject }.to change { migration.reload.batch_size }.to(2_000_000)
end
context 'when max_batch_size is set' do
let(:max_batch_size) { 10000 }
let(:migration_params) { { max_batch_size: max_batch_size } }
it 'caps the batch size at max_batch_size' do
mock_efficiency(0.7)
expect { subject }.to change { migration.reload.batch_size }.to(max_batch_size)
end
end
end
context 'reaching the lower limit for the batch size' do
let(:batch_size) { 1_050 }
it 'caps the batch size at 1k' do
mock_efficiency(1.1)
expect { subject }.to change { migration.reload.batch_size }.to(1_000)
end
end
context 'when migration max_batch_size is less than MIN_BATCH_SIZE' do
let(:migration_params) { { max_batch_size: 900 } }
it 'does not raise an error' do
mock_efficiency(0.7)
expect { subject }.not_to raise_error
end
end
end
end