From bfc892a2555acc89c1ae4d34e96a9cf99427ac33 Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Tue, 17 Oct 2017 11:07:15 -0700 Subject: turboize arrays Signed-off-by: Lamont Granquist --- lib/chef/node/immutable_collections.rb | 46 ++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb index 3378bee2b5..4edaf586cd 100644 --- a/lib/chef/node/immutable_collections.rb +++ b/lib/chef/node/immutable_collections.rb @@ -132,6 +132,7 @@ class Chef def reset @generated_cache = false + @short_circuit_attr_level = nil internal_clear # redundant? end @@ -141,13 +142,26 @@ class Chef @generated_cache = true end + # This can be set to e.g. [ :@default ] by the parent container to cause this container + # to only use the default level and to bypass deep merging (the common case is either + # default-level or automatic-level and we aren't doing any deep merging). Right now it + # "optimized" for the case where we're no longer merging anything and only tracking a + # single level, and setting this to anything other than a size=1 array would behave + # in a broken fashion. That could be fixed, but the perf boost would likely not be + # that large in the typical case. + # + # @api private + attr_accessor :short_circuit_attr_levels + private + # deep merging of array attribute within normal and override where they are merged together def combined_components(components) combined_values = nil components.each do |component| values = __node__.attributes.instance_variable_get(component).read(*__path__) next unless values.is_a?(Array) + @tracked_components << component combined_values ||= [] combined_values += values end @@ -157,6 +171,7 @@ class Chef def get_array(component) array = __node__.attributes.instance_variable_get(component).read(*__path__) if array.is_a?(Array) + @tracked_components << component array end # else nil end @@ -164,14 +179,25 @@ class Chef def generate_cache internal_clear components = [] - components << combined_components(Attribute::DEFAULT_COMPONENTS) - components << get_array(:@normal) - components << combined_components(Attribute::OVERRIDE_COMPONENTS) - components << get_array(:@automatic) + @tracked_components = [] + if short_circuit_attr_levels + components << get_array(short_circuit_attr_levels.first) + else + components << combined_components(Attribute::DEFAULT_COMPONENTS) + components << get_array(:@normal) + components << combined_components(Attribute::OVERRIDE_COMPONENTS) + components << get_array(:@automatic) + end highest = components.compact.last if highest.is_a?(Array) internal_replace( highest.each_with_index.map { |x, i| convert_value(x, __path__ + [ i ] ) } ) end + if @tracked_components.size == 1 + # tracked_components is accurate enough to tell us if we're not really merging + internal_each do |key, value| + value.short_circuit_attr_levels = @tracked_components if value.respond_to?(:short_circuit_attr_levels) + end + end end # needed for __path__ @@ -283,12 +309,12 @@ class Chef def generate_cache internal_clear components = short_circuit_attr_levels ? short_circuit_attr_levels : Attribute::COMPONENTS.reverse - # merged_components is not entirely accurate due to the short-circuit - merged_components = [] + # tracked_components is not entirely accurate due to the short-circuit + tracked_components = [] components.each do |component| subhash = __node__.attributes.instance_variable_get(component).read(*__path__) unless subhash.nil? # FIXME: nil is used for not present - merged_components << component + tracked_components << component if subhash.kind_of?(Hash) subhash.keys.each do |key| next if internal_key?(key) @@ -299,10 +325,10 @@ class Chef end end end - if merged_components.size == 1 - # merged_components is accurate enough to tell us if we're not really merging + if tracked_components.size == 1 + # tracked_components is accurate enough to tell us if we're not really merging internal_each do |key, value| - value.short_circuit_attr_levels = merged_components if value.respond_to?(:short_circuit_attr_levels) + value.short_circuit_attr_levels = tracked_components if value.respond_to?(:short_circuit_attr_levels) end end end -- cgit v1.2.1