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 16:59:54 -0700
commitecce615820fac0aab53a2ab41dcbc7e28c3a5514 (patch)
tree910763b50722be38e33114da7660c1d328879516
parent37f3241392ecebd6be7aeffc3e0d8152b9c22e5e (diff)
downloadchef-ecce615820fac0aab53a2ab41dcbc7e28c3a5514.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 29b60a98d5..6dc94e4af5 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
@@ -450,17 +450,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)