Skip to content

Commit 3f64a32

Browse files
authored
Performance fixes for permission queries (#5172)
PR #5157 introduced authorized_space_ids_subquery and authorized_org_ids_subquery. These methods avoid unnecessary subplans on the spaces / organizations tables on every permission lookup and are now also used by: - Permissions#readable_security_group_guids_query - Permissions#readable_space_quota_guids - Permissions#is_org_manager? - Membership#authorized_space_guids_subquery - Membership#authorized_org_guids_subquery - Service-credential-binding fetchers - Service-offering / service-plan list fetchers The service-offering / service-plan list fetchers now take both *_ids_query and *_query; the id-query feeds the always-executed permission filter, the full query is consulted only on guid-filtered requests. Also removes the now-dead 'membership' helper from v3/application_controller.rb (no V3 controller calls it after #5094).
1 parent 76c42e7 commit 3f64a32

16 files changed

Lines changed: 152 additions & 75 deletions

app/controllers/v3/application_controller.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,4 @@ def handle_exception(error)
268268
def null_coalesce_body
269269
hashed_params[:body] ||= {}
270270
end
271-
272-
def membership
273-
@membership ||= Membership.new(current_user)
274-
end
275271
end

app/controllers/v3/service_credential_bindings_controller.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def index
2222
invalid_param!(message.errors.full_messages) unless message.valid?
2323

2424
results = list_fetcher.fetch(
25-
readable_spaces_query: spaces_query,
25+
readable_space_ids_query: space_ids_query,
2626
message: message,
2727
eager_loaded_associations: Presenters::V3::ServiceCredentialBindingPresenter.associated_resources
2828
)
@@ -332,14 +332,14 @@ def fetch_credentials_value(name)
332332
end
333333

334334
def service_credential_binding
335-
@service_credential_binding ||= fetcher.fetch(hashed_params[:guid], readable_spaces_query: spaces_query)
335+
@service_credential_binding ||= fetcher.fetch(hashed_params[:guid], readable_space_ids_query: space_ids_query)
336336
end
337337

338-
def spaces_query
338+
def space_ids_query
339339
if permission_queryer.can_read_globally?
340340
nil
341341
else
342-
permission_queryer.readable_spaces_query
342+
permission_queryer.readable_space_ids_query
343343
end
344344
end
345345

app/controllers/v3/service_offerings_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ def index
3535
ServiceOfferingListFetcher.fetch(
3636
message,
3737
eager_loaded_associations: Presenters::V3::ServiceOfferingPresenter.associated_resources,
38+
readable_org_ids_query: permission_queryer.readable_org_ids_query,
3839
readable_orgs_query: permission_queryer.readable_orgs_query,
40+
readable_space_ids_query: permission_queryer.readable_space_scoped_space_ids_query,
3941
readable_spaces_query: permission_queryer.readable_space_scoped_spaces_query
4042
)
4143
end

app/controllers/v3/service_plans_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ def index
3535
ServicePlanListFetcher.fetch(
3636
message,
3737
eager_loaded_associations: Presenters::V3::ServicePlanPresenter.associated_resources,
38+
readable_org_ids_query: permission_queryer.readable_org_ids_query,
3839
readable_orgs_query: permission_queryer.readable_orgs_query,
40+
readable_space_ids_query: permission_queryer.readable_space_scoped_space_ids_query,
3941
readable_spaces_query: permission_queryer.readable_space_scoped_spaces_query
4042
)
4143
end

app/fetchers/base_service_list_fetcher.rb

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ class BaseServiceListFetcher < BaseListFetcher
66
class << self
77
private
88

9-
def fetch(klass, message, omniscient: false, readable_orgs_query: nil, readable_spaces_query: nil, eager_loaded_associations: [])
9+
def fetch(klass, message, omniscient: false,
10+
readable_org_ids_query: nil, readable_orgs_query: nil,
11+
readable_space_ids_query: nil, readable_spaces_query: nil,
12+
eager_loaded_associations: [])
1013
# The base dataset for the given model; other tables might be joined later on for filtering,
1114
# but we are only interested in the columns from the base table.
1215
dataset = klass.dataset.select_all(klass.table_name)
@@ -15,10 +18,10 @@ def fetch(klass, message, omniscient: false, readable_orgs_query: nil, readable_
1518
dataset = filter(message, dataset, klass)
1619

1720
# Filter by permissions granted on org level for plans.
18-
plan_dataset = readable_by_plan_org(dataset, readable_orgs_query)
21+
plan_dataset = readable_by_plan_org(dataset, readable_org_ids_query)
1922

2023
# Filter by permissions granted on space level for brokers.
21-
broker_dataset = readable_by_broker_space(dataset, readable_spaces_query)
24+
broker_dataset = readable_by_broker_space(dataset, readable_space_ids_query)
2225

2326
# Apply additional filtering by org / space guids (if requested).
2427
if message.requested?(:organization_guids)
@@ -27,8 +30,9 @@ def fetch(klass, message, omniscient: false, readable_orgs_query: nil, readable_
2730
plan_dataset,
2831
broker_dataset,
2932
omniscient,
33+
readable_org_ids_query,
3034
readable_orgs_query,
31-
readable_spaces_query,
35+
readable_space_ids_query,
3236
dataset
3337
)
3438
end
@@ -39,7 +43,8 @@ def fetch(klass, message, omniscient: false, readable_orgs_query: nil, readable_
3943
plan_dataset,
4044
broker_dataset,
4145
omniscient,
42-
readable_orgs_query,
46+
readable_org_ids_query,
47+
readable_space_ids_query,
4348
readable_spaces_query,
4449
dataset
4550
)
@@ -66,36 +71,38 @@ def fetch(klass, message, omniscient: false, readable_orgs_query: nil, readable_
6671
dataset.eager(eager_loaded_associations)
6772
end
6873

69-
def readable_by_plan_org(dataset, readable_orgs_query)
70-
return if readable_orgs_query.nil?
74+
def readable_by_plan_org(dataset, readable_org_ids_query)
75+
return if readable_org_ids_query.nil?
7176

7277
plan_dataset = dataset.clone
7378
plan_dataset = join_plan_org_visibilities(plan_dataset)
74-
plan_dataset.where { Sequel[:service_plan_visibilities][:organization_id] =~ readable_orgs_query.select(:id) }
79+
plan_dataset.where { Sequel[:service_plan_visibilities][:organization_id] =~ readable_org_ids_query }
7580
end
7681

77-
def readable_by_broker_space(dataset, readable_spaces_query)
78-
return if readable_spaces_query.nil?
82+
def readable_by_broker_space(dataset, readable_space_ids_query)
83+
return if readable_space_ids_query.nil?
7984

8085
broker_dataset = dataset.clone
8186
broker_dataset = join_service_brokers(broker_dataset)
82-
broker_dataset.where { Sequel[:service_brokers][:space_id] =~ readable_spaces_query.select(:id) }
87+
broker_dataset.where { Sequel[:service_brokers][:space_id] =~ readable_space_ids_query }
8388
end
8489

85-
def filter_by_org_guid(org_guids, plan_dataset, broker_dataset, omniscient, readable_orgs_query, readable_spaces_query, dataset)
90+
# The readable_orgs_query projects the readable guid set against the user-supplied filter.
91+
# The readable_org_ids_query / readable_space_ids_query gate which sub-datasets are included.
92+
def filter_by_org_guid(org_guids, plan_dataset, broker_dataset, omniscient, readable_org_ids_query, readable_orgs_query, readable_space_ids_query, dataset)
8693
authorized_org_guids = if !omniscient && !readable_orgs_query.nil?
8794
readable_orgs_query.where(guid: org_guids).select_map(:guid)
8895
else
8996
org_guids
9097
end
9198

92-
if omniscient || !readable_orgs_query.nil?
99+
if omniscient || !readable_org_ids_query.nil?
93100
plan_dataset = dataset.clone if plan_dataset.nil?
94101
plan_dataset = join_plan_orgs(plan_dataset)
95102
plan_dataset = plan_dataset.where { Sequel[:plan_orgs][:guid] =~ authorized_org_guids }
96103
end
97104

98-
if omniscient || !readable_spaces_query.nil?
105+
if omniscient || !readable_space_ids_query.nil?
99106
broker_dataset = dataset.clone if broker_dataset.nil?
100107
broker_dataset = join_broker_orgs(broker_dataset)
101108
broker_dataset = broker_dataset.where { Sequel[:broker_orgs][:guid] =~ authorized_org_guids }
@@ -104,20 +111,22 @@ def filter_by_org_guid(org_guids, plan_dataset, broker_dataset, omniscient, read
104111
[plan_dataset, broker_dataset]
105112
end
106113

107-
def filter_by_space_guid(space_guids, plan_dataset, broker_dataset, omniscient, readable_orgs_query, readable_spaces_query, dataset)
114+
# The readable_spaces_query projects the readable guid set against the user-supplied filter.
115+
# The readable_org_ids_query / readable_space_ids_query gate which sub-datasets are included.
116+
def filter_by_space_guid(space_guids, plan_dataset, broker_dataset, omniscient, readable_org_ids_query, readable_space_ids_query, readable_spaces_query, dataset)
108117
authorized_space_guids = if !omniscient && !readable_spaces_query.nil?
109118
readable_spaces_query.where(guid: space_guids).select_map(:guid)
110119
else
111120
space_guids
112121
end
113122

114-
if omniscient || !readable_orgs_query.nil?
123+
if omniscient || !readable_org_ids_query.nil?
115124
plan_dataset = dataset.clone if plan_dataset.nil?
116125
plan_dataset = join_plan_spaces(plan_dataset)
117126
plan_dataset = plan_dataset.where { Sequel[:plan_spaces][:guid] =~ authorized_space_guids }
118127
end
119128

120-
if omniscient || !readable_spaces_query.nil?
129+
if omniscient || !readable_space_ids_query.nil?
121130
broker_dataset = dataset.clone if broker_dataset.nil?
122131
broker_dataset = join_broker_spaces(broker_dataset)
123132
broker_dataset = broker_dataset.where { Sequel[:broker_spaces][:guid] =~ authorized_space_guids }

app/fetchers/service_credential_binding_fetcher.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
module VCAP
44
module CloudController
55
class ServiceCredentialBindingFetcher
6-
def fetch(guid, readable_spaces_query: nil)
7-
list_fetcher.fetch(readable_spaces_query:).first(guid:)
6+
def fetch(guid, readable_space_ids_query: nil)
7+
list_fetcher.fetch(readable_space_ids_query:).first(guid:)
88
end
99

1010
private

app/fetchers/service_credential_binding_list_fetcher.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ class << self
1818
service_offering_guid
1919
].freeze
2020

21-
def fetch(readable_spaces_query: nil, message: nil, eager_loaded_associations: [])
22-
dataset = case readable_spaces_query
21+
def fetch(readable_space_ids_query: nil, message: nil, eager_loaded_associations: [])
22+
dataset = case readable_space_ids_query
2323
when nil
2424
ServiceCredentialBinding::View.dataset
2525
else
26-
ServiceCredentialBinding::View.where { Sequel[:space_id] =~ readable_spaces_query.select(:id) }
26+
ServiceCredentialBinding::View.where { Sequel[:space_id] =~ readable_space_ids_query }
2727
end
2828

2929
dataset = dataset.eager(eager_loaded_associations)

app/fetchers/service_offering_list_fetcher.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
module VCAP::CloudController
44
class ServiceOfferingListFetcher < BaseServiceListFetcher
55
class << self
6-
def fetch(message, omniscient: false, readable_orgs_query: nil, readable_spaces_query: nil, eager_loaded_associations: [])
6+
def fetch(message, omniscient: false,
7+
readable_org_ids_query: nil, readable_orgs_query: nil,
8+
readable_space_ids_query: nil, readable_spaces_query: nil,
9+
eager_loaded_associations: [])
710
super(Service,
811
message,
912
omniscient:,
13+
readable_org_ids_query:,
1014
readable_orgs_query:,
15+
readable_space_ids_query:,
1116
readable_spaces_query:,
1217
eager_loaded_associations:)
1318
end

app/fetchers/service_plan_list_fetcher.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
module VCAP::CloudController
44
class ServicePlanListFetcher < BaseServiceListFetcher
55
class << self
6-
def fetch(message, omniscient: false, readable_orgs_query: nil, readable_spaces_query: nil, eager_loaded_associations: [])
6+
def fetch(message, omniscient: false,
7+
readable_org_ids_query: nil, readable_orgs_query: nil,
8+
readable_space_ids_query: nil, readable_spaces_query: nil,
9+
eager_loaded_associations: [])
710
super(ServicePlan,
811
message,
912
omniscient: omniscient,
13+
readable_org_ids_query: readable_org_ids_query,
1014
readable_orgs_query: readable_orgs_query,
15+
readable_space_ids_query: readable_space_ids_query,
1116
readable_spaces_query: readable_spaces_query,
1217
eager_loaded_associations: eager_loaded_associations.append(:orgs_visibility))
1318
end

lib/cloud_controller/membership.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def authorized_org_guids(roles)
2525
end
2626

2727
def authorized_org_guids_subquery(roles)
28-
authorized_orgs_subquery(roles).select(:guid)
28+
Organization.where(id: authorized_org_ids_subquery(roles)).select(:guid)
2929
end
3030

3131
def authorized_orgs_subquery(roles)
@@ -50,7 +50,7 @@ def authorized_space_guids(roles)
5050
end
5151

5252
def authorized_space_guids_subquery(roles)
53-
authorized_spaces_subquery(roles).select(:guid)
53+
Space.where(id: authorized_space_ids_subquery(roles)).select(:guid)
5454
end
5555

5656
def authorized_spaces_subquery(roles)

0 commit comments

Comments
 (0)