summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2017-10-17 11:07:15 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2017-10-17 11:07:39 -0700
commitef37db79b3dd58b254c63a1779a7c880a9f8855f (patch)
tree18e0669ed0cf52995226a340a0f59e942de491c9
parent03c8ac0de9ad9c9b09d118652ce1d1c65be7d83c (diff)
downloadchef-ef37db79b3dd58b254c63a1779a7c880a9f8855f.tar.gz
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r--lib/chef/node/immutable_collections.rb46
1 files changed, 36 insertions, 10 deletions
diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb
index 5bb32008d6..18eb3b8771 100644
--- a/lib/chef/node/immutable_collections.rb
+++ b/lib/chef/node/immutable_collections.rb
@@ -129,6 +129,7 @@ class Chef
def reset
@generated_cache = false
+ @short_circuit_attr_level = nil
internal_clear # redundant?
end
@@ -138,13 +139,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
@@ -154,6 +168,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
@@ -161,14 +176,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__
@@ -303,12 +329,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)
@@ -319,10 +345,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