# frozen_string_literal: truerequire"active_support/core_ext/object/duplicable"require"active_support/core_ext/string/inflections"require"active_support/per_thread_registry"moduleActiveSupportmoduleCachemoduleStrategy# Caches that implement LocalCache will be backed by an in-memory cache for the# duration of a block. Repeated calls to the cache for the same key will hit the# in-memory cache for faster access.moduleLocalCacheautoload:Middleware,"active_support/cache/strategy/local_cache_middleware"# Class for storing and registering the local caches.classLocalCacheRegistry# :nodoc:extendActiveSupport::PerThreadRegistrydefinitialize@registry={}enddefcache_for(local_cache_key)@registry[local_cache_key]enddefset_cache_for(local_cache_key,value)@registry[local_cache_key]=valueenddefself.set_cache_for(l,v);instance.set_cache_forl,v;enddefself.cache_for(l);instance.cache_forl;endend# Simple memory backed cache. This cache is not thread safe and is intended only# for serving as a temporary memory cache for a single thread.classLocalStore<Storedefinitializesuper@data={}end# Don't allow synchronizing since it isn't thread safe.defsynchronize# :nodoc:yieldenddefclear(options=nil)@data.clearenddefread_entry(key,options)@data[key]enddefread_multi_entries(keys,options)values={}keys.eachdo|name|entry=read_entry(name,options)values[name]=entry.valueifentryendvaluesenddefwrite_entry(key,value,options)@data[key]=valuetrueenddefdelete_entry(key,options)!!@data.delete(key)enddeffetch_entry(key,options=nil)# :nodoc:@data.fetch(key){@data[key]=yield}endend# Use a local cache for the duration of block.defwith_local_cacheuse_temporary_local_cache(LocalStore.new){yield}end# Middleware class can be inserted as a Rack handler to be local cache for the# duration of request.defmiddleware@middleware||=Middleware.new("ActiveSupport::Cache::Strategy::LocalCache",local_cache_key)enddefclear(options=nil)# :nodoc:returnsuperunlesscache=local_cachecache.clear(options)superenddefcleanup(options=nil)# :nodoc:returnsuperunlesscache=local_cachecache.clearsuperenddefincrement(name,amount=1,options=nil)# :nodoc:returnsuperunlesslocal_cachevalue=bypass_local_cache{super}write_cache_value(name,value,options)valueenddefdecrement(name,amount=1,options=nil)# :nodoc:returnsuperunlesslocal_cachevalue=bypass_local_cache{super}write_cache_value(name,value,options)valueendprivatedefread_entry(key,options)ifcache=local_cachecache.fetch_entry(key){super}elsesuperendenddefread_multi_entries(keys,options)returnsuperunlesslocal_cachelocal_entries=local_cache.read_multi_entries(keys,options)missed_keys=keys-local_entries.keysifmissed_keys.any?local_entries.merge!(super(missed_keys,options))elselocal_entriesendenddefwrite_entry(key,entry,options)ifoptions[:unless_exist]local_cache.delete_entry(key,options)iflocal_cacheelselocal_cache.write_entry(key,entry,options)iflocal_cacheendsuperenddefdelete_entry(key,options)local_cache.delete_entry(key,options)iflocal_cachesuperenddefwrite_cache_value(name,value,options)name=normalize_key(name,options)cache=local_cachecache.mutedoifvaluecache.write(name,value,options)elsecache.delete(name,options)endendenddeflocal_cache_key@local_cache_key||="#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/,"_").to_symenddeflocal_cacheLocalCacheRegistry.cache_for(local_cache_key)enddefbypass_local_cacheuse_temporary_local_cache(nil){yield}enddefuse_temporary_local_cache(temporary_cache)save_cache=LocalCacheRegistry.cache_for(local_cache_key)beginLocalCacheRegistry.set_cache_for(local_cache_key,temporary_cache)yieldensureLocalCacheRegistry.set_cache_for(local_cache_key,save_cache)endendendendendend