Skip to content

Commit

Permalink
(PUP-9931) Use ruby threadlocal implementation
Browse files Browse the repository at this point in the history
If we cycle out JRuby instances while using the Java ThreadLocal class,
we end up retaining references to the old JRuby instances. A simple
solution to this is to use the native ruby ThreadLocalVar
implementation, so that when a JRuby instance is GCd everything
stored on the ruby Thread class will be collected as well.
  • Loading branch information
pcarlisle committed Sep 9, 2019
1 parent ca79621 commit 9182bc3
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 4 deletions.
8 changes: 4 additions & 4 deletions lib/puppet/context.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'concurrent'
require 'puppet/thread_local'

# Puppet::Context is a system for tracking services and contextual information
# that puppet needs to be able to run. Values are "bound" in a context when it is created
Expand All @@ -21,12 +21,12 @@ class DuplicateRollbackMarkError < Puppet::Error; end

# @api private
def initialize(initial_bindings)
@stack = Concurrent::ThreadLocalVar.new(EmptyStack.new.push(initial_bindings))
@stack = Puppet::ThreadLocal.new(EmptyStack.new.push(initial_bindings))

# By initializing @rollbacks to nil and creating a hash lazily when #mark or
# #rollback are called we ensure that the hashes are never shared between
# threads and it's safe to mutate them
@rollbacks = Concurrent::ThreadLocalVar.new(nil)
@rollbacks = Puppet::ThreadLocal.new(nil)
end

# @api private
Expand All @@ -39,7 +39,7 @@ def push(overrides, description = '')
#
# @api private
def unsafe_push_global(overrides, description = '')
@stack = Concurrent::ThreadLocalVar.new(
@stack = Puppet::ThreadLocal.new(
@stack.value.push(overrides, description)
)
end
Expand Down
7 changes: 7 additions & 0 deletions lib/puppet/thread_local.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'concurrent'

# We want to use the pure Ruby implementation even on JRuby. If we use the Java
# implementation of ThreadLocal, we end up leaking references to JRuby instances
# and preventing them from being garbage collected.
class Puppet::ThreadLocal < Concurrent::RubyThreadLocalVar
end

0 comments on commit 9182bc3

Please sign in to comment.