Skip to content

Commit 0a626f1

Browse files
committed
(PUP-11373) Always lock the environment before its type collection
Puppetserver in MT mode can deadlock if one thread calls into the loaders, which locks the environment, and then tries to lock the type_collection: - waiting to lock <3f27e688> (a org.jruby.gen.RubyObject0) owned by "qtp346358872-131" t@131 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb:188 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb:152 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb:152 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/pops/loader/runtime3_type_loader.rb:79 ... /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/concurrent/lock.rb:10 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/pops/loader/loader.rb:153 While another thread locks the type_collection and tries to lock the environment: - waiting to lock <bd0f663> (a org.jruby.gen.RubyObject0) owned by "qtp346358872-67" t@76 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/node/environment.rb:248 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/parser/type_loader.rb:131 ... /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb:203 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/concurrent/lock.rb:10 /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb:188 This commit orders locking so we always acquire the environment lock before its type collection lock.
1 parent bd47bdd commit 0a626f1

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

lib/puppet/resource/type_collection.rb

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def initialize(env)
2424
@definitions = {}
2525
@nodes = {}
2626
@notfound = {}
27+
# always lock the environment before acquiring this lock
2728
@lock = Puppet::Concurrent::Lock.new
2829

2930
# So we can keep a list and match the first-defined regex
@@ -185,26 +186,29 @@ def version
185186
# Resolve namespaces and find the given object. Autoload it if
186187
# necessary.
187188
def find_or_load(name, type)
188-
@lock.synchronize do
189-
# Name is always absolute, but may start with :: which must be removed
190-
fqname = (name[0,2] == COLON_COLON ? name[2..-1] : name)
191-
192-
result = send(type, fqname)
193-
unless result
194-
if @notfound[ fqname ] && Puppet[ :ignoremissingtypes ]
195-
# do not try to autoload if we already tried and it wasn't conclusive
196-
# as this is a time consuming operation. Warn the user.
197-
# Check first if debugging is on since the call to debug_once is expensive
198-
if Puppet[:debug]
199-
debug_once _("Not attempting to load %{type} %{fqname} as this object was missing during a prior compilation") % { type: type, fqname: fqname }
189+
# always lock the environment before locking the type collection
190+
@environment.lock.synchronize do
191+
@lock.synchronize do
192+
# Name is always absolute, but may start with :: which must be removed
193+
fqname = (name[0,2] == COLON_COLON ? name[2..-1] : name)
194+
195+
result = send(type, fqname)
196+
unless result
197+
if @notfound[ fqname ] && Puppet[ :ignoremissingtypes ]
198+
# do not try to autoload if we already tried and it wasn't conclusive
199+
# as this is a time consuming operation. Warn the user.
200+
# Check first if debugging is on since the call to debug_once is expensive
201+
if Puppet[:debug]
202+
debug_once _("Not attempting to load %{type} %{fqname} as this object was missing during a prior compilation") % { type: type, fqname: fqname }
203+
end
204+
else
205+
fqname = munge_name(fqname)
206+
result = loader.try_load_fqname(type, fqname)
207+
@notfound[ fqname ] = result.nil?
200208
end
201-
else
202-
fqname = munge_name(fqname)
203-
result = loader.try_load_fqname(type, fqname)
204-
@notfound[ fqname ] = result.nil?
205209
end
210+
result
206211
end
207-
result
208212
end
209213
end
210214

0 commit comments

Comments
 (0)