提交 9f84e60a 编写于 作者: T thedarkone 提交者: Aaron Patterson

Make DescendantsTracker thread safe and optimize the #descendants method.

上级 4f106bbb
......@@ -2,35 +2,50 @@ module ActiveSupport
# This module provides an internal implementation to track descendants
# which is faster than iterating through ObjectSpace.
module DescendantsTracker
@@direct_descendants = Hash.new { |h, k| h[k] = [] }
@@direct_descendants = {}
def self.direct_descendants(klass)
@@direct_descendants[klass]
end
class << self
def direct_descendants(klass)
@@direct_descendants[klass] || []
end
def self.descendants(klass)
@@direct_descendants[klass].inject([]) do |descendants, _klass|
descendants << _klass
descendants.concat _klass.descendants
def descendants(klass)
arr = []
accumulate_descendants(klass, arr)
arr
end
end
def self.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) }
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] ||= []) << descendant
end
private
def accumulate_descendants(klass, acc)
if direct_descendants = @@direct_descendants[klass]
acc.concat(direct_descendants)
direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
end
else
@@direct_descendants.clear
end
end
def inherited(base)
self.direct_descendants << base
DescendantsTracker.store_inherited(self, base)
super
end
......
require 'set'
module DescendantsTrackerTestCases
class Parent
extend ActiveSupport::DescendantsTracker
......@@ -18,15 +20,15 @@ class Grandchild2 < Child1
ALL = [Parent, Child1, Child2, Grandchild1, Grandchild2]
def test_descendants
assert_equal [Child1, Grandchild1, Grandchild2, Child2], Parent.descendants
assert_equal [Grandchild1, Grandchild2], Child1.descendants
assert_equal [], Child2.descendants
assert_equal_sets [Child1, Grandchild1, Grandchild2, Child2], Parent.descendants
assert_equal_sets [Grandchild1, Grandchild2], Child1.descendants
assert_equal_sets [], Child2.descendants
end
def test_direct_descendants
assert_equal [Child1, Child2], Parent.direct_descendants
assert_equal [Grandchild1, Grandchild2], Child1.direct_descendants
assert_equal [], Child2.direct_descendants
assert_equal_sets [Child1, Child2], Parent.direct_descendants
assert_equal_sets [Grandchild1, Grandchild2], Child1.direct_descendants
assert_equal_sets [], Child2.direct_descendants
end
def test_clear
......@@ -40,6 +42,10 @@ def test_clear
protected
def assert_equal_sets(expected, actual)
Set.new(expected) == Set.new(actual)
end
def mark_as_autoloaded(*klasses)
# If ActiveSupport::Dependencies is not loaded, forget about autoloading.
# This allows using AS::DescendantsTracker without AS::Dependencies.
......
......@@ -18,17 +18,17 @@ def test_clear_with_autoloaded_parent_children_and_granchildren
def test_clear_with_autoloaded_children_and_granchildren
mark_as_autoloaded Child1, Grandchild1, Grandchild2 do
ActiveSupport::DescendantsTracker.clear
assert_equal [Child2], Parent.descendants
assert_equal [], Child2.descendants
assert_equal_sets [Child2], Parent.descendants
assert_equal_sets [], Child2.descendants
end
end
def test_clear_with_autoloaded_granchildren
mark_as_autoloaded Grandchild1, Grandchild2 do
ActiveSupport::DescendantsTracker.clear
assert_equal [Child1, Child2], Parent.descendants
assert_equal [], Child1.descendants
assert_equal [], Child2.descendants
assert_equal_sets [Child1, Child2], Parent.descendants
assert_equal_sets [], Child1.descendants
assert_equal_sets [], Child2.descendants
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册