aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/concurrent_hash.rb26
-rw-r--r--activesupport/lib/active_support/memoizable.rb38
3 files changed, 65 insertions, 0 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 7ebb3c48e0..62d538e2d5 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -32,6 +32,7 @@ module ActiveSupport
autoload :BufferedLogger, 'active_support/buffered_logger'
autoload :Cache, 'active_support/cache'
autoload :Callbacks, 'active_support/callbacks'
+ autoload :ConcurrentHash, 'active_support/concurrent_hash'
autoload :Deprecation, 'active_support/deprecation'
autoload :Duration, 'active_support/duration'
autoload :Gzip, 'active_support/gzip'
diff --git a/activesupport/lib/active_support/concurrent_hash.rb b/activesupport/lib/active_support/concurrent_hash.rb
new file mode 100644
index 0000000000..c9f9b16da3
--- /dev/null
+++ b/activesupport/lib/active_support/concurrent_hash.rb
@@ -0,0 +1,26 @@
+module ActiveSupport
+ class ConcurrentHash
+ def initialize(hash = {})
+ @backup_cache = hash.dup
+ @frozen_cache = hash.dup.freeze
+ @mutex = Mutex.new
+ end
+
+ def []=(k,v)
+ @mutex.synchronize { @backup_cache[k] = v }
+ @frozen_cache = @backup_cache.dup.freeze
+ end
+
+ def [](k)
+ if @frozen_cache.key?(k)
+ @frozen_cache[k]
+ else
+ @mutex.synchronize { @backup_cache[k] }
+ end
+ end
+
+ def empty?
+ @backup_cache.empty?
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 4ffb5d9520..8e9abeaf91 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -1,4 +1,42 @@
module ActiveSupport
+ class ConcurrentHash
+ def initialize(hash = {})
+ @backup_cache = hash.dup
+ @frozen_cache = hash.dup.freeze
+ @mutex = Mutex.new
+ end
+
+ def []=(k,v)
+ @mutex.synchronize { @backup_cache[k] = v }
+ @frozen_cache = @backup_cache.dup.freeze
+ end
+
+ def [](k)
+ if @frozen_cache.key?(k)
+ @frozen_cache[k]
+ else
+ @mutex.synchronize { @backup_cache[k] }
+ end
+ end
+
+ def empty?
+ @backup_cache.empty?
+ end
+ end
+
+ module SafelyMemoizable
+ def safely_memoize(*symbols)
+ symbols.each do |symbol|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{symbol}(*args)
+ memoized = @_memoized_#{symbol} || ::ActiveSupport::ConcurrentHash.new
+ memoized[args] ||= memoized_#{symbol}(*args)
+ end
+ RUBY
+ end
+ end
+ end
+
module Memoizable
def self.memoized_ivar_for(symbol)
"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym