# frozen_string_literal: truerequire"active_support/core_ext/string/inflections"moduleActiveSupportmoduleCachemoduleStrategy# = Local \Cache \Strategy## 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.moduleLocalCacheRegistry# :nodoc:extendselfdefcache_for(local_cache_key)registry=ActiveSupport::IsolatedExecutionState[:active_support_local_cache_registry]||={}registry[local_cache_key]enddefset_cache_for(local_cache_key,value)registry=ActiveSupport::IsolatedExecutionState[:active_support_local_cache_registry]||={}registry[local_cache_key]=valueendend# = Local \Cache \Store## 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.classLocalStoredefinitialize@data={}enddefclear(options=nil)@data.clearenddefread_entry(key)@data[key]enddefread_multi_entries(keys)@data.slice(*keys)enddefwrite_entry(key,entry)@data[key]=entrytrueenddefdelete_entry(key)!!@data.delete(key)enddeffetch_entry(key)# :nodoc:@data.fetch(key){@data[key]=yield}endend# Use a local cache for the duration of block.defwith_local_cache(&block)use_temporary_local_cache(LocalStore.new,&block)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.clear(options)superenddefdelete_matched(matcher,options=nil)# :nodoc:returnsuperunlesscache=local_cachecache.clear(options)superenddefincrement(name,amount=1,**options)# :nodoc:returnsuperunlesslocal_cachevalue=bypass_local_cache{super}write_cache_value(name,value,raw: true,**options)valueenddefdecrement(name,amount=1,**options)# :nodoc:returnsuperunlesslocal_cachevalue=bypass_local_cache{super}write_cache_value(name,value,raw: true,**options)valueenddeffetch_multi(*names,&block)# :nodoc:returnsuperiflocal_cache.nil?||names.empty?options=names.extract_options!options=merged_options(options)keys_to_names=names.index_by{|name|normalize_key(name,options)}local_entries=local_cache.read_multi_entries(keys_to_names.keys)results=local_entries.each_with_object({})do|(key,value),result|# If we recorded a miss in the local cache, `#fetch_multi` will forward# that key to the real store, and the entry will be replaced# local_cache.delete_entry(key)nextifvalue.nil?entry=deserialize_entry(value,**options)normalized_key=keys_to_names[key]ifentry.nil?result[normalized_key]=nilelsifentry.expired?||entry.mismatched?(normalize_version(normalized_key,options))local_cache.delete_entry(key)elseresult[normalized_key]=entry.valueendendifresults.size<names.sizeresults.merge!(super(*(names-results.keys),options,&block))endresultsendprivatedefread_serialized_entry(key,raw: false,**options)ifcache=local_cachehit=trueentry=cache.fetch_entry(key)dohit=falsesuperendoptions[:event][:store]=cache.class.nameifhit&&options[:event]entryelsesuperendenddefread_multi_entries(names,**options)returnsuperunlesslocal_cachekeys_to_names=names.index_by{|name|normalize_key(name,options)}local_entries=local_cache.read_multi_entries(keys_to_names.keys)results=local_entries.each_with_object({})do|(key,value),result|nextifvalue.nil?# recorded cache missentry=deserialize_entry(value,**options)normalized_key=keys_to_names[key]ifentry.nil?result[normalized_key]=nilelsifentry.expired?||entry.mismatched?(normalize_version(normalized_key,options))local_cache.delete_entry(key)elseresult[normalized_key]=entry.valueendendifresults.size<names.sizeresults.merge!(super(names-results.keys,**options))endresultsenddefwrite_serialized_entry(key,payload,**)ifreturn_value=superlocal_cache.write_entry(key,payload)iflocal_cacheelselocal_cache.delete_entry(key)iflocal_cacheendreturn_valueenddefdelete_entry(key,**)local_cache.delete_entry(key)iflocal_cachesuperenddefwrite_cache_value(name,value,**options)name=normalize_key(name,options)cache=local_cacheifvaluecache.write_entry(name,serialize_entry(new_entry(value,**options),**options))elsecache.delete_entry(name)endenddeflocal_cache_key@local_cache_key||="#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/,"_").to_symenddeflocal_cacheLocalCacheRegistry.cache_for(local_cache_key)enddefbypass_local_cache(&block)use_temporary_local_cache(nil,&block)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