Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 08f824a

Browse files
committedJan 8, 2025··
Refactor optimized relation reader
1 parent 520bc19 commit 08f824a

File tree

8 files changed

+74
-54
lines changed

8 files changed

+74
-54
lines changed
 

‎core/lib/rom/container.rb

+12
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ def self.new(gateways, relations, mappers, commands)
110110
end
111111
end
112112

113+
# Container lock
114+
#
115+
# @api private
116+
attr_reader :lock
117+
118+
# @api private
119+
def initialize
120+
super
121+
122+
@lock = ::Mutex.new
123+
end
124+
113125
# Return registered gateways
114126
#
115127
# @return [Hash<Symbol=>Gateway>]

‎core/lib/rom/plugins/relation/registry_reader.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class RegistryReader < ::Module
1414
EMPTY_REGISTRY = RelationRegistry.build(EMPTY_HASH).freeze
1515

1616
# @api private
17-
def initialize(klass:, relation_readers_module:)
17+
def initialize(readers:)
1818
super()
19-
klass.include relation_readers_module
19+
include readers
2020
end
2121

2222
# @api private

‎core/lib/rom/setup/finalize/finalize_relations.rb

+8-10
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ class Finalize
99
class FinalizeRelations
1010
attr_reader :notifications
1111

12-
module BuildRelationReaders
13-
def self.build(relations)
14-
Module.new do
15-
relations.each do |name|
16-
define_method(name) do
17-
__registry__[name]
18-
end
19-
end
12+
class RegistryReaders < ::Module
13+
def initialize(relations)
14+
super()
15+
16+
relations.each do |name|
17+
define_method(name) { __registry__[name] }
2018
end
2119
end
2220
end
@@ -44,7 +42,7 @@ def initialize(gateways, relation_classes, notifications:, mappers: nil, plugins
4442
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
4543
def run!
4644
relation_registry = RelationRegistry.new do |registry, relations|
47-
relation_readers_module = BuildRelationReaders.build(relation_names)
45+
registry_readers = RegistryReaders.new(relation_names)
4846
@relation_classes.each do |klass|
4947
unless klass.adapter
5048
raise MissingAdapterIdentifierError,
@@ -58,7 +56,7 @@ def run!
5856
"Relation with name #{key.inspect} registered more than once"
5957
end
6058

61-
klass.use(:registry_reader, klass: klass, relation_readers_module: relation_readers_module)
59+
klass.use(:registry_reader, readers: registry_readers)
6260

6361
notifications.trigger(
6462
'configuration.relations.class.ready',

‎repository/lib/rom/repository/class_interface.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ def new(container = nil, **options)
6060
container ||= options.fetch(:container)
6161

6262
unless relation_reader
63-
relation_reader(RelationReader.new(self, container.relations.elements.keys))
64-
include(relation_reader)
63+
reader = RelationReader.new(
64+
relations: container.relations.elements.keys,
65+
lock: container.lock
66+
)
67+
relation_reader(reader)
68+
include(reader)
6569
end
6670

6771
super(**options, container: container)

‎repository/lib/rom/repository/relation_reader.rb

+44-37
Original file line numberDiff line numberDiff line change
@@ -7,70 +7,77 @@ class RelationReader < ::Module
77
extend ::Dry::Core::ClassAttributes
88

99
# @api private
10-
attr_reader :klass
11-
12-
# @api private
13-
attr_reader :relations
14-
1510
defines :relation_readers
1611

17-
defines :mutex
18-
mutex(Mutex.new)
19-
20-
defines :relation_cache
21-
relation_cache(Concurrent::Hash.new)
22-
2312
module InstanceMethods
2413
# @api private
25-
def set_relation(name) # rubocop:disable Naming/AccessorMethodName
14+
def prepare_relation(name)
2615
container
2716
.relations[name]
28-
.with(auto_struct: auto_struct, struct_namespace: struct_namespace)
17+
.with(
18+
auto_struct: auto_struct,
19+
struct_namespace: struct_namespace
20+
)
2921
end
3022

23+
# @api private
3124
def relation_reader(name, relation_cache)
3225
key = [name, auto_struct, struct_namespace]
33-
relation_cache[key] ||= set_relation(name)
26+
relation_cache[key] ||= prepare_relation(name)
3427
end
3528
end
3629

3730
# @api private
38-
def mutex
39-
ROM::Repository::RelationReader.mutex
40-
end
31+
class Readers < ::Module
32+
# @api private
33+
attr_reader :cache
4134

42-
# @api private
43-
def initialize(klass, relations)
44-
super()
45-
@relations = relations
46-
mutex.synchronize do
47-
unless self.class.relation_readers
48-
self.class.relation_readers(
49-
build_relation_readers(relations, self.class.relation_cache)
50-
)
35+
def initialize(relations)
36+
super()
37+
cache = ::Concurrent::Hash.new
38+
39+
relations.each do |name|
40+
define_readers_for_relation(name, cache)
41+
end
42+
end
43+
44+
# @api private
45+
def define_readers_for_relation(name, cache)
46+
define_method(name) do
47+
relation_reader(name, cache)
5148
end
5249
end
53-
klass.include self.class.relation_readers
5450
end
5551

5652
# @api private
57-
def included(klass)
58-
super
59-
klass.include(InstanceMethods)
60-
end
53+
def initialize(relations:, lock:)
54+
super()
6155

62-
private
56+
include relation_readers(relations:, lock:)
57+
end
6358

6459
# @api private
65-
def build_relation_readers(relations, relation_cache)
66-
Module.new do
67-
relations.each do |name|
68-
define_method(name) do
69-
relation_reader(name, relation_cache)
60+
def relation_readers(relations:, lock:)
61+
existing = self.class.relation_readers
62+
63+
if existing.nil?
64+
lock.synchronize do
65+
unless self.class.relation_readers
66+
self.class.relation_readers Readers.new(relations)
7067
end
7168
end
69+
70+
self.class.relation_readers
71+
else
72+
existing
7273
end
7374
end
75+
76+
# @api private
77+
def included(klass)
78+
super
79+
klass.include(InstanceMethods)
80+
end
7481
end
7582
end
7683
end

‎repository/lib/rom/repository/root.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def self.inherited(klass)
5858
# @see Repository#initialize
5959
def initialize(*, **)
6060
super
61-
@root = set_relation(self.class.root)
61+
@root = prepare_relation(self.class.root)
6262
end
6363
end
6464
end

‎repository/spec/integration/plugin_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def self.apply(target, **)
1212
target.prepend(self)
1313
end
1414

15-
def set_relation(*)
15+
def prepare_relation(*)
1616
super.where { `1 = 0` }
1717
end
1818
end

‎repository/spec/spec_helper.rb

-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ def self.remove_constants
5959
config.after do
6060
Test.remove_constants
6161
ROM::Repository::RelationReader.relation_readers(nil)
62-
ROM::Repository::RelationReader.relation_cache(Concurrent::Hash.new)
6362
end
6463

6564
Dir[SPEC_ROOT.join('support/*.rb').to_s].each do |f|

0 commit comments

Comments
 (0)
Please sign in to comment.