Commit 39ae284d authored by Andreas Brandl's avatar Andreas Brandl

Merge branch 'ah-extend-monthly-partitioning-strategy' into 'master'

Retain non-empty partitions

See merge request gitlab-org/gitlab!69850
parents ccb48123 6ee9cb78
...@@ -4,17 +4,18 @@ module Gitlab ...@@ -4,17 +4,18 @@ module Gitlab
module Database module Database
module Partitioning module Partitioning
class MonthlyStrategy class MonthlyStrategy
attr_reader :model, :partitioning_key, :retain_for attr_reader :model, :partitioning_key, :retain_for, :retain_non_empty_partitions
# We create this many partitions in the future # We create this many partitions in the future
HEADROOM = 6.months HEADROOM = 6.months
delegate :table_name, to: :model delegate :table_name, to: :model
def initialize(model, partitioning_key, retain_for: nil) def initialize(model, partitioning_key, retain_for: nil, retain_non_empty_partitions: false)
@model = model @model = model
@partitioning_key = partitioning_key @partitioning_key = partitioning_key
@retain_for = retain_for @retain_for = retain_for
@retain_non_empty_partitions = retain_non_empty_partitions
end end
def current_partitions def current_partitions
...@@ -29,7 +30,10 @@ module Gitlab ...@@ -29,7 +30,10 @@ module Gitlab
end end
def extra_partitions def extra_partitions
current_partitions - desired_partitions partitions = current_partitions - desired_partitions
partitions.reject!(&:holds_data?) if retain_non_empty_partitions
partitions
end end
private private
......
...@@ -69,6 +69,10 @@ module Gitlab ...@@ -69,6 +69,10 @@ module Gitlab
partition_name <=> other.partition_name partition_name <=> other.partition_name
end end
def holds_data?
conn.execute("SELECT 1 FROM #{fully_qualified_partition} LIMIT 1").ntuples > 0
end
private private
def date_or_nil(obj) def date_or_nil(obj)
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
let(:connection) { ActiveRecord::Base.connection }
describe '#current_partitions' do describe '#current_partitions' do
subject { described_class.new(model, partitioning_key).current_partitions } subject { described_class.new(model, partitioning_key).current_partitions }
...@@ -11,7 +13,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do ...@@ -11,7 +13,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
let(:table_name) { :partitioned_test } let(:table_name) { :partitioned_test }
before do before do
ActiveRecord::Base.connection.execute(<<~SQL) connection.execute(<<~SQL)
CREATE TABLE #{table_name} CREATE TABLE #{table_name}
(id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at))
PARTITION BY RANGE (created_at); PARTITION BY RANGE (created_at);
...@@ -52,7 +54,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do ...@@ -52,7 +54,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
context 'with existing partitions' do context 'with existing partitions' do
before do before do
ActiveRecord::Base.connection.execute(<<~SQL) connection.execute(<<~SQL)
CREATE TABLE #{model.table_name} CREATE TABLE #{model.table_name}
(id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at))
PARTITION BY RANGE (created_at); PARTITION BY RANGE (created_at);
...@@ -113,7 +115,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do ...@@ -113,7 +115,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
context 'without existing partitions' do context 'without existing partitions' do
before do before do
ActiveRecord::Base.connection.execute(<<~SQL) connection.execute(<<~SQL)
CREATE TABLE #{model.table_name} CREATE TABLE #{model.table_name}
(id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at))
PARTITION BY RANGE (created_at); PARTITION BY RANGE (created_at);
...@@ -159,7 +161,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do ...@@ -159,7 +161,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
context 'with a regular partition but no catchall (MINVALUE, to) partition' do context 'with a regular partition but no catchall (MINVALUE, to) partition' do
before do before do
ActiveRecord::Base.connection.execute(<<~SQL) connection.execute(<<~SQL)
CREATE TABLE #{model.table_name} CREATE TABLE #{model.table_name}
(id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at))
PARTITION BY RANGE (created_at); PARTITION BY RANGE (created_at);
...@@ -248,6 +250,25 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do ...@@ -248,6 +250,25 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: 'partitioned_test_202005') Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: 'partitioned_test_202005')
) )
end end
context 'when the retain_non_empty_partitions is true' do
subject { described_class.new(model, partitioning_key, retain_for: 2.months, retain_non_empty_partitions: true).extra_partitions }
it 'prunes empty partitions' do
expect(subject).to contain_exactly(
Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01', partition_name: 'partitioned_test_000000'),
Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: 'partitioned_test_202005')
)
end
it 'does not prune non-empty partitions' do
connection.execute("INSERT INTO #{table_name} (created_at) VALUES (('2020-05-15'))") # inserting one record into partitioned_test_202005
expect(subject).to contain_exactly(
Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01', partition_name: 'partitioned_test_000000')
)
end
end
end end
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