Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FINE] Truncate realtime metrics instead of purging #17124

Merged
merged 3 commits into from
Mar 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/models/metric.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@ class Metric < ApplicationRecord
BASE_COLS = ["id", "timestamp", "capture_interval_name", "resource_type", "resource_id", "resource_name", "tag_names", "parent_host_id", "parent_ems_cluster_id", "parent_ems_id", "parent_storage_id"]

include Metric::Common

# @param time [ActiveSupport::TimeWithZone, Time, Integer, nil] the hour to run (default: 1 hour from now)
# @return the table for the given hour
# Unfortunatly, Integer responds_to :hour, so :strftime was used instead.
def self.reindex_table_name(time = Time.now.utc.hour + 1)
hour = (time.respond_to?(:strftime) ? time.hour : time) % 24
"metrics_%02d" % hour
end
end
34 changes: 33 additions & 1 deletion app/models/metric/purging.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ def self.purge_count(older_than, interval)
purge_scope(older_than, interval).count
end

# Used for MetricRollup (not Metric)
# A list of ids (not a scope) is brought in and associated vimPerformanceTagValue records are deleted
#
# TODO: Would be more efficient to just use the full scope here (not id list)
# - we would then just use the standard purge_in_batches
# - remove the to_a from purge_in_batches
# - possibly use the standard purge_in_batches
# - change the metrics rollups to use truncate instead
def self.purge_associated_records(metric_type, ids)
# Since VimPerformanceTagValues are 6 * number of tags per performance
# record, we need to batch in smaller trips.
Expand All @@ -85,9 +93,33 @@ def self.purge_hourly(older_than, window = nil, total_limit = nil, &block)
end

def self.purge_realtime(older_than, window = nil, total_limit = nil, &block)
purge_by_date(older_than, "realtime", window, total_limit, &block)
truncate_child_tables(older_than)
end

# truncate metrics child tables
# Determines hours not being preserved and truncates them
# Used for realtime metrics.
def self.truncate_child_tables(older_than)
target_hours = determine_target_hours(older_than, Time.now.utc)
return if target_hours.blank?

target_hours.each do |hour|
Metric.connection.truncate(Metric.reindex_table_name(hour), "Metric Truncate table #{hour}")
end
end

def self.determine_target_hours(older_than, end_date)
return [] if (end_date - older_than) > 24.hours

start_hour = older_than.utc.hour
end_hour = end_date.utc.hour
end_hour += 24 if start_hour > end_hour

good_hours = (start_hour..end_hour).map { |h| h % 24 }
(0..23).to_a - good_hours.to_a
end
private_class_method :determine_target_hours

def self.purge(older_than, interval, window = nil, total_limit = nil, &block)
purge_by_date(older_than, interval, window, total_limit, &block)
end
Expand Down
104 changes: 104 additions & 0 deletions spec/models/metric/purging_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,108 @@
end
end
end

context "#purge_realtime" do
before { EvmSpecHelper.create_guid_miq_server_zone }
let(:vm1) { FactoryGirl.create(:vm_vmware) }

it "deletes mid day" do
Timecop.freeze('2018-02-01T09:12:00Z') do
(0..16).each do |hours|
FactoryGirl.create(:metric_vm_rt, :resource_id => vm1.id, :timestamp => (hours.hours.ago + 1.minute))
end
expect(Metric.count).to eq(17)
# keep metric for 05:13 - 09:13
# note: old metrics will delete metrics at 09:14..09:59 - the new metrics will keep those
described_class.purge_realtime(4.hours.ago)
expect(Metric.all.map { |metric| metric.timestamp.hour }.sort).to eq [5, 6, 7, 8, 9]
expect(Metric.count).to eq(5)
end
end

it "deletes just after midnight" do
Timecop.freeze('2018-02-01T02:12:00Z') do
(0..16).each do |hours|
FactoryGirl.create(:metric_vm_rt, :resource_id => vm1.id, :timestamp => (hours.hours.ago + 1.minute))
end
expect(Metric.count).to eq(17)
# keep metric for 22:13 - 02:13
described_class.purge_realtime(4.hours.ago)
expect(Metric.all.map { |metric| metric.timestamp.hour }.sort).to eq [0, 1, 2, 22, 23]
expect(Metric.count).to eq(5)
end
end

it "deletes just after new years" do
EvmSpecHelper.create_guid_miq_server_zone

Timecop.freeze('2018-01-01T02:12:00Z') do
(0..16).each do |hours|
FactoryGirl.create(:metric_vm_rt, :resource_id => vm1.id, :timestamp => (hours.hours.ago + 1.minute))
end
expect(Metric.count).to eq(17)
# keep metric for 22:13 - 02:13
described_class.purge_realtime(4.hours.ago)
expect(Metric.all.map { |metric| metric.timestamp.hour }.sort).to eq [0, 1, 2, 22, 23]
expect(Metric.count).to eq(5)
end
end

it "deletes just after daylight savings (spring forward)" do
EvmSpecHelper.create_guid_miq_server_zone
Timecop.freeze('2017-03-12T08:12:00Z') do # 2:00am+05 EST is time of change
# this is overkill. since we prune every 21 minutes, there will only be ~1 table with data
(0..16).each do |hours|
FactoryGirl.create(:metric_vm_rt, :resource_id => vm1.id, :timestamp => (hours.hours.ago + 1.minute))
end
expect(Metric.count).to eq(17)
# keep metric for 04:13 - 08:13
described_class.purge_realtime(4.hours.ago)
expect(Metric.all.map { |metric| metric.timestamp.hour }.sort).to eq [4, 5, 6, 7, 8]
expect(Metric.count).to eq(5)
end
end

it "deletes just after daylight savings (fallback)" do
EvmSpecHelper.create_guid_miq_server_zone
Timecop.freeze('2017-11-05T08:12:00Z') do # 2:00am+05 EST is time of change
# this is overkill. since we prune every 21 minutes, there will only be ~1 table with data
(0..16).each do |hours|
FactoryGirl.create(:metric_vm_rt, :resource_id => vm1.id, :timestamp => (hours.hours.ago + 1.minute))
end
expect(Metric.count).to eq(17)
# keep metric for 04:13 - 08:13
described_class.purge_realtime(4.hours.ago)
expect(Metric.all.map { |metric| metric.timestamp.hour }.sort).to eq [4, 5, 6, 7, 8]
expect(Metric.count).to eq(5)
end
end

context "with 8 hour retention" do
# since the window duration is passed into the queue / this method, this config change will not matter
let(:settings) do
{
:performance => {
:history => {
:keep_realtime_performance => "8.hours",
:purge_window_size => 10,
}
}
}
end

it "deletes just after midnight" do
Timecop.freeze('2018-02-01T02:12:00Z') do
(0..23).each do |hours|
FactoryGirl.create(:metric_vm_rt, :resource_id => vm1.id, :timestamp => (hours.hours.ago + 1.minute))
end
expect(Metric.count).to eq(24)
# keep metric for 18:13 - 02:13
described_class.purge_realtime(8.hours.ago)
expect(Metric.all.map { |metric| metric.timestamp.hour }.sort).to eq [0, 1, 2, 18, 19, 20, 21, 22, 23]
expect(Metric.count).to eq(9)
end
end
end
end
end
28 changes: 28 additions & 0 deletions spec/models/metric_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,34 @@
end
end

context "#reindex_table_name" do
it "defaults to 1 hour from now" do
Timecop.freeze("2017-01-30T09:20UTC") do
expect(Metric.reindex_table_name).to eq("metrics_10")
end
end

it "pads table to 2 digits" do
Timecop.freeze("2017-01-30T03:20UTC") do
expect(Metric.reindex_table_name).to eq("metrics_04")
end
end

it "provides hour wrap around" do
Timecop.freeze("2017-01-30T23:20UTC") do
expect(Metric.reindex_table_name).to eq("metrics_00")
end
end

it "allows time to be passed in" do
expect(Metric.reindex_table_name(Time.parse("2017-01-30T23:20Z").utc)).to eq("metrics_23")
end

it "allows hour integer to be passed in" do
expect(Metric.reindex_table_name(23)).to eq("metrics_23")
end
end

private

def assert_queued_rollup(q_item, instance_id, class_name, args, deliver_on, method = "perf_rollup")
Expand Down