From 3b8cc74c59fad6efad3334c457daff3c929d1f24 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Fri, 12 Jul 2019 10:10:33 -0400 Subject: [PATCH 1/5] Cache computed attribute options Merging the default and the attribute specific options was resulting in a lot of memory allocations --- lib/jsonapi/basic_resource.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/jsonapi/basic_resource.rb b/lib/jsonapi/basic_resource.rb index da9042658..0a933efef 100644 --- a/lib/jsonapi/basic_resource.rb +++ b/lib/jsonapi/basic_resource.rb @@ -453,6 +453,8 @@ def inherited(subclass) subclass._routed = false subclass._warned_missing_route = false + + subclass._clear_cached_attribute_options end def rebuild_relationships(relationships) @@ -527,6 +529,8 @@ def attributes(*attrs) end def attribute(attribute_name, options = {}) + _clear_cached_attribute_options + attr = attribute_name.to_sym check_reserved_attribute_name(attr) @@ -826,7 +830,7 @@ def verify_relationship_filter(filter, raw, _context = nil) # quasi private class methods def _attribute_options(attr) - default_attribute_options.merge(@_attributes[attr]) + @_cached_attribute_options[attr] ||= default_attribute_options.merge(@_attributes[attr]) end def _attribute_delegated_name(attr) @@ -1107,6 +1111,10 @@ def register_relationship(name, relationship_object) @_relationships[name] = relationship_object end + def _clear_cached_attribute_options + @_cached_attribute_options = {} + end + private def check_reserved_resource_name(type, name) From ca1baa00e9bee825a6918256fad158cb23dad993 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Fri, 12 Jul 2019 12:01:24 -0400 Subject: [PATCH 2/5] Cache custom_generation_options options This hash only needs to be computed once, and repeatedly building it results in a lot of memory allocations. --- lib/jsonapi/resource_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jsonapi/resource_serializer.rb b/lib/jsonapi/resource_serializer.rb index e5749a98e..5751adb67 100644 --- a/lib/jsonapi/resource_serializer.rb +++ b/lib/jsonapi/resource_serializer.rb @@ -230,7 +230,7 @@ def attributes_hash(source, fetchable_fields) end def custom_generation_options - { + @_custom_generation_options ||= { serializer: self, serialization_options: @serialization_options } From 7d753ec60cf1438c7ad6c421606c8e4f8907af5f Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Fri, 12 Jul 2019 12:03:34 -0400 Subject: [PATCH 3/5] Cache fields Reset the cache if the relationships or the attributes change --- lib/jsonapi/basic_resource.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/jsonapi/basic_resource.rb b/lib/jsonapi/basic_resource.rb index 0a933efef..ea8b19ea7 100644 --- a/lib/jsonapi/basic_resource.rb +++ b/lib/jsonapi/basic_resource.rb @@ -455,6 +455,7 @@ def inherited(subclass) subclass._warned_missing_route = false subclass._clear_cached_attribute_options + subclass._clear_fields_cache end def rebuild_relationships(relationships) @@ -530,6 +531,7 @@ def attributes(*attrs) def attribute(attribute_name, options = {}) _clear_cached_attribute_options + _clear_fields_cache attr = attribute_name.to_sym @@ -697,7 +699,7 @@ def sortable_field?(key, context = nil) end def fields - _relationships.keys | _attributes.keys + @_fields_cache ||= _relationships.keys | _attributes.keys end def resources_for(records, context) @@ -1067,6 +1069,8 @@ def construct_order_options(sort_params) end def _add_relationship(klass, *attrs) + _clear_fields_cache + options = attrs.extract_options! options[:parent_resource] = self @@ -1115,6 +1119,10 @@ def _clear_cached_attribute_options @_cached_attribute_options = {} end + def _clear_fields_cache + @_fields_cache = nil + end + private def check_reserved_resource_name(type, name) From c6e75ac3e5099a32e5ff0bbc087c1458246ff8b4 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Fri, 12 Jul 2019 12:04:41 -0400 Subject: [PATCH 4/5] Optimize resource_path generation to reduce string allocations --- lib/jsonapi/link_builder.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/jsonapi/link_builder.rb b/lib/jsonapi/link_builder.rb index 99cd6223c..c591efc3d 100644 --- a/lib/jsonapi/link_builder.rb +++ b/lib/jsonapi/link_builder.rb @@ -127,12 +127,11 @@ def resources_path(source_klass) end def resource_path(source) - url = "#{resources_path(source.class)}" - - unless source.class.singleton? - url = "#{url}/#{source.id}" + if source.class.singleton? + resources_path(source.class) + else + "#{resources_path(source.class)}/#{source.id}" end - url end def resource_url(source) From 388824b1cf3b15d2ad27463fc864b047690a4258 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Fri, 12 Jul 2019 13:30:38 -0400 Subject: [PATCH 5/5] Cache resources_paths per class Optimization for memory allocation --- lib/jsonapi/link_builder.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/jsonapi/link_builder.rb b/lib/jsonapi/link_builder.rb index c591efc3d..6ede8a022 100644 --- a/lib/jsonapi/link_builder.rb +++ b/lib/jsonapi/link_builder.rb @@ -123,7 +123,8 @@ def module_scopes_from_class(klass) end def resources_path(source_klass) - formatted_module_path_from_class(source_klass) + format_route(source_klass._type.to_s) + @_resources_path ||= {} + @_resources_path[source_klass] ||= formatted_module_path_from_class(source_klass) + format_route(source_klass._type.to_s) end def resource_path(source)