Skip to content

Commit 8508a76

Browse files
committed
Add lifecycle index to usage event tables
Add a composite [state, <guid>, id] index on app_usage_events and service_usage_events to support the keep-running cleanup's correlated lookups of related lifecycle events and the backfill's existence checks. Created concurrently on Postgres. The task lifecycle's correlated lookups (keyed by task_guid) are served by the existing app_usage_events_task_guid_index -- a task has only a handful of events, so probing by task_guid alone stays cheap and no [state, task_guid, id] index is needed.
1 parent 4fc337c commit 8508a76

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Sequel.migration do
2+
no_transaction # to use the 'concurrently' option
3+
4+
up do
5+
if database_type == :postgres
6+
VCAP::Migration.with_concurrent_timeout(self) do
7+
add_index :app_usage_events, %i[state app_guid id],
8+
name: :app_usage_events_lifecycle_index,
9+
if_not_exists: true,
10+
concurrently: true
11+
12+
add_index :service_usage_events, %i[state service_instance_guid id],
13+
name: :service_usage_events_lifecycle_index,
14+
if_not_exists: true,
15+
concurrently: true
16+
end
17+
18+
elsif database_type == :mysql
19+
alter_table :app_usage_events do
20+
# rubocop:disable Sequel/ConcurrentIndex
21+
add_index %i[state app_guid id], name: :app_usage_events_lifecycle_index unless @db.indexes(:app_usage_events).include?(:app_usage_events_lifecycle_index)
22+
# rubocop:enable Sequel/ConcurrentIndex
23+
end
24+
25+
alter_table :service_usage_events do
26+
# rubocop:disable Sequel/ConcurrentIndex
27+
unless @db.indexes(:service_usage_events).include?(:service_usage_events_lifecycle_index)
28+
add_index %i[state service_instance_guid id],
29+
name: :service_usage_events_lifecycle_index
30+
end
31+
# rubocop:enable Sequel/ConcurrentIndex
32+
end
33+
end
34+
end
35+
36+
down do
37+
if database_type == :postgres
38+
VCAP::Migration.with_concurrent_timeout(self) do
39+
drop_index :app_usage_events, %i[state app_guid id],
40+
name: :app_usage_events_lifecycle_index,
41+
if_exists: true,
42+
concurrently: true
43+
44+
drop_index :service_usage_events, %i[state service_instance_guid id],
45+
name: :service_usage_events_lifecycle_index,
46+
if_exists: true,
47+
concurrently: true
48+
end
49+
end
50+
51+
if database_type == :mysql
52+
alter_table :app_usage_events do
53+
# rubocop:disable Sequel/ConcurrentIndex
54+
drop_index %i[state app_guid id], name: :app_usage_events_lifecycle_index if @db.indexes(:app_usage_events).include?(:app_usage_events_lifecycle_index)
55+
# rubocop:enable Sequel/ConcurrentIndex
56+
end
57+
58+
alter_table :service_usage_events do
59+
# rubocop:disable Sequel/ConcurrentIndex
60+
if @db.indexes(:service_usage_events).include?(:service_usage_events_lifecycle_index)
61+
drop_index %i[state service_instance_guid id],
62+
name: :service_usage_events_lifecycle_index
63+
end
64+
# rubocop:enable Sequel/ConcurrentIndex
65+
end
66+
end
67+
end
68+
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
require 'spec_helper'
2+
require 'migrations/helpers/migration_shared_context'
3+
4+
RSpec.describe 'migration to add the lifecycle index to the usage event tables', isolation: :truncation, type: :migration do
5+
include_context 'migration' do
6+
let(:migration_filename) { '20260601120000_add_lifecycle_index_to_usage_events.rb' }
7+
end
8+
9+
let(:run_migration) do
10+
Sequel::Migrator.run(db, migrations_path, target: current_migration_index, allow_missing_migration_files: true)
11+
end
12+
13+
let(:revert_migration) do
14+
Sequel::Migrator.run(db, migrations_path, target: current_migration_index - 1, allow_missing_migration_files: true)
15+
end
16+
17+
it 'adds the lifecycle index to both usage event tables (idempotently) and removes it on revert' do
18+
# Before migration: the lifecycle indexes should not exist.
19+
expect(db.indexes(:app_usage_events)).not_to include(:app_usage_events_lifecycle_index)
20+
expect(db.indexes(:service_usage_events)).not_to include(:service_usage_events_lifecycle_index)
21+
22+
# Up migration adds both indexes with the expected column order.
23+
expect { run_migration }.not_to raise_error
24+
expect(db.indexes(:app_usage_events)).to include(:app_usage_events_lifecycle_index)
25+
expect(db.indexes(:service_usage_events)).to include(:service_usage_events_lifecycle_index)
26+
expect(db.indexes(:app_usage_events)[:app_usage_events_lifecycle_index][:columns]).to eq(%i[state app_guid id])
27+
expect(db.indexes(:service_usage_events)[:service_usage_events_lifecycle_index][:columns]).to eq(%i[state service_instance_guid id])
28+
29+
# Up migration is idempotent: running again does not fail.
30+
expect { run_migration }.not_to raise_error
31+
expect(db.indexes(:app_usage_events)).to include(:app_usage_events_lifecycle_index)
32+
expect(db.indexes(:service_usage_events)).to include(:service_usage_events_lifecycle_index)
33+
34+
# Down migration removes both indexes.
35+
expect { revert_migration }.not_to raise_error
36+
expect(db.indexes(:app_usage_events)).not_to include(:app_usage_events_lifecycle_index)
37+
expect(db.indexes(:service_usage_events)).not_to include(:service_usage_events_lifecycle_index)
38+
39+
# Down migration is idempotent: running again does not fail.
40+
expect { revert_migration }.not_to raise_error
41+
expect(db.indexes(:app_usage_events)).not_to include(:app_usage_events_lifecycle_index)
42+
expect(db.indexes(:service_usage_events)).not_to include(:service_usage_events_lifecycle_index)
43+
end
44+
end

0 commit comments

Comments
 (0)