summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2022-03-30 13:19:32 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2022-03-30 13:19:32 -0700
commit84d1f174842472dd87e322659beb65253f621a2b (patch)
tree48c3a51579c2e947a63406acdee14663df100a06
parent1a55973dced382442e4ad85f167af106c0b2945a (diff)
downloadchef-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.rb51
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)