Skip to content

Commit

Permalink
Merge pull request #695 from Cygnetise/memory_optimisations
Browse files Browse the repository at this point in the history
Reduce the retained memory when defining the relation readers
  • Loading branch information
solnic authored Aug 2, 2024
2 parents 4676769 + a39ac5c commit 24405f8
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 24 deletions.
17 changes: 2 additions & 15 deletions core/lib/rom/plugins/relation/registry_reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@ class RegistryReader < ::Module
EMPTY_REGISTRY = RelationRegistry.build(EMPTY_HASH).freeze

# @api private
attr_reader :relations

# @api private
def initialize(relations:)
@relations = relations
define_readers!
def initialize(klass:, relation_readers_module:)
klass.include relation_readers_module
end

# @api private
Expand All @@ -29,15 +25,6 @@ def included(klass)

klass.option :__registry__, default: -> { EMPTY_REGISTRY }
end

private

# @api private
def define_readers!
relations.each do |name|
define_method(name) { __registry__[name] }
end
end
end
end
end
Expand Down
15 changes: 14 additions & 1 deletion core/lib/rom/setup/finalize/finalize_relations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ class Finalize
class FinalizeRelations
attr_reader :notifications

module BuildRelationReaders
def self.build(relations)
Module.new do
relations.each do |name|
define_method(name) do
__registry__[name]
end
end
end
end
end

# Build relation registry of specified descendant classes
#
# This is used by the setup
Expand All @@ -30,6 +42,7 @@ def initialize(gateways, relation_classes, notifications:, mappers: nil, plugins
# @api private
def run!
relation_registry = RelationRegistry.new do |registry, relations|
relation_readers_module = BuildRelationReaders.build(relation_names)
@relation_classes.each do |klass|
unless klass.adapter
raise MissingAdapterIdentifierError,
Expand All @@ -43,7 +56,7 @@ def run!
"Relation with name #{key.inspect} registered more than once"
end

klass.use(:registry_reader, relations: relation_names)
klass.use(:registry_reader, klass: klass, relation_readers_module: relation_readers_module)

notifications.trigger('configuration.relations.class.ready', relation: klass, adapter: klass.adapter)

Expand Down
42 changes: 34 additions & 8 deletions repository/lib/rom/repository/relation_reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,50 @@ module ROM
class Repository
# @api private
class RelationReader < Module
extend Dry::Core::ClassAttributes

# @api private
attr_reader :klass

# @api private
attr_reader :relations

defines :relation_readers

defines :mutex
mutex(Mutex.new)

defines :relation_cache
relation_cache(Concurrent::Hash.new)

module InstanceMethods
# @api private
def set_relation(name)
container
.relations[name]
.with(auto_struct: auto_struct)
.struct_namespace(struct_namespace)
.with(auto_struct: auto_struct, struct_namespace: struct_namespace)
end

def relation_reader(name, relation_cache)
key = [name, auto_struct, struct_namespace]
relation_cache[key] ||= set_relation(name)
end
end

# @api private
def mutex
ROM::Repository::RelationReader.mutex
end

# @api private
def initialize(klass, relations)
@klass = klass
@relations = relations
define_readers!
mutex.synchronize do
unless self.class.relation_readers
self.class.relation_readers(build_relation_readers(relations, self.class.relation_cache))
end
end
klass.include self.class.relation_readers
end

# @api private
Expand All @@ -33,13 +56,16 @@ def included(klass)
klass.include(InstanceMethods)
end


private

# @api private
def define_readers!
relations.each do |name|
define_method(name) do
@relations[name] ||= set_relation(name)
def build_relation_readers(relations, relation_cache)
Module.new do
relations.each do |name|
define_method(name) do
relation_reader(name, relation_cache)
end
end
end
end
Expand Down

0 comments on commit 24405f8

Please sign in to comment.