diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2022-03-30 13:19:32 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2022-03-30 13:19:32 -0700 |
commit | 84d1f174842472dd87e322659beb65253f621a2b (patch) | |
tree | 48c3a51579c2e947a63406acdee14663df100a06 | |
parent | 1a55973dced382442e4ad85f167af106c0b2945a (diff) | |
download | chef-84d1f174842472dd87e322659beb65253f621a2b.tar.gz |
Fix attribute performance issues in node.read
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r-- | lib/chef/node/attribute.rb | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb index 6a8e72004b..9be5293815 100644 --- a/lib/chef/node/attribute.rb +++ b/lib/chef/node/attribute.rb @@ -38,7 +38,7 @@ class Chef include Immutablize # FIXME: what is include Enumerable doing up here, when down below we delegate - # most of the Enumerable/Hash things to the underlying merged ImmutableHash. That + # most of the Enumerable/Hash things to the underlying merged ImmutableMash. That # is, in fact, the correct, thing to do, while including Enumerable to try to create # a hash-like API gets lots of things wrong because of the difference between the # Hash `each do |key, value|` vs the Array-like `each do |value|` API that Enumerable @@ -452,17 +452,60 @@ class Chef # method-style access to attributes (has to come after the prepended ImmutablizeHash) def read(*path) - merged_attributes.read(*path) + rest = path.dup + first = rest.shift + + # this will have terrible performance, but it is the only way to get at the entire + # merged ImmutableMash top level object. + return merged_attributes if first.nil? + + obj = self[first] + if obj.is_a?(ImmutableMash) || obj.is_a?(ImmutableArray) + obj.read(*rest) + else + obj + end end alias :dig :read def read!(*path) - merged_attributes.read!(*path) + rest = path.dup + first = rest.shift + + # this will have terrible performance, but it is the only way to get at the entire + # merged ImmutableMash top level object. + return merged_attributes if first.nil? + + raise Chef::Exceptions::NoSuchAttribute.new(path.join ".") unless key?(first) + + obj = self[first] + + return obj if rest.empty? + + if obj.is_a?(ImmutableMash) || obj.is_a?(ImmutableArray) + obj.read!(*rest) + else + raise Chef::Exceptions::NoSuchAttribute.new(path.join ".") + end end def exist?(*path) - merged_attributes.exist?(*path) + rest = path.dup + first = rest.shift + + return true if first.nil? + + return false unless key?(first) + + return true if rest.empty? + + obj = self[first] + if obj.is_a?(ImmutableMash) || obj.is_a?(ImmutableArray) + obj.exist?(*rest) + else + false + end end def write(level, *args, &block) |