Created
January 6, 2019 23:21
-
-
Save budu/a34bc4ce7e528dfbb109b739162497ff to your computer and use it in GitHub Desktop.
Modified DescendantsTracker that doesn't leak memory (but might cause other problems)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# see https://github.com/rails/rails/pull/31442 | |
require 'weakref' | |
module ActiveSupport | |
# This module provides an internal implementation to track descendants | |
# which is faster than iterating through ObjectSpace. | |
module DescendantsTracker | |
@@direct_descendants = {} | |
class << self | |
def direct_descendants(klass) | |
descendants = @@direct_descendants[klass] | |
descendants ? descendants.to_a : [] | |
end | |
def descendants(klass) | |
arr = [] | |
accumulate_descendants(klass, arr) | |
arr | |
end | |
def clear | |
if defined? ActiveSupport::Dependencies | |
@@direct_descendants.each do |klass, descendants| | |
if ActiveSupport::Dependencies.autoloaded?(klass) | |
@@direct_descendants.delete(klass) | |
else | |
descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) } | |
end | |
end | |
else | |
@@direct_descendants.clear | |
end | |
end | |
# This is the only method that is not thread safe, but is only ever called | |
# during the eager loading phase. | |
def store_inherited(klass, descendant) | |
(@@direct_descendants[klass] ||= DescendantsArray.new) << descendant | |
end | |
private | |
def accumulate_descendants(klass, acc) | |
if direct_descendants = @@direct_descendants[klass] | |
direct_descendants.each do |direct_descendant| | |
acc << direct_descendant | |
accumulate_descendants(direct_descendant, acc) | |
end | |
end | |
end | |
end | |
def inherited(base) | |
DescendantsTracker.store_inherited(self, base) | |
super | |
end | |
def direct_descendants | |
DescendantsTracker.direct_descendants(self) | |
end | |
def descendants | |
DescendantsTracker.descendants(self) | |
end | |
# DescendantsArray is an array that contains weak references to classes. | |
class DescendantsArray # :nodoc: | |
include Enumerable | |
def initialize | |
@refs = [] | |
end | |
def initialize_copy(orig) | |
@refs = @refs.dup | |
end | |
def <<(klass) | |
cleanup! | |
@refs << WeakRef.new(klass) | |
end | |
def each | |
@refs.each do |ref| | |
begin | |
yield ref.__getobj__ | |
rescue WeakRef::RefError | |
end | |
end | |
end | |
def refs_size | |
@refs.size | |
end | |
def cleanup! | |
@refs.delete_if { |ref| !ref.weakref_alive? } | |
end | |
def reject! | |
@refs.reject! do |ref| | |
begin | |
yield ref.__getobj__ | |
rescue WeakRef::RefError | |
true | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment