Class: Sfn::Cache
- Inherits:
 - 
      Object
      
        
- Object
 - Sfn::Cache
 
 
- Defined in:
 - lib/sfn/cache.rb
 
Overview
Data caching helper
Defined Under Namespace
Classes: LocalLock, LocalValue, Stamped
Instance Attribute Summary collapse
- 
  
    
      #key  ⇒ String 
    
    
  
  
  
  
    
      readonly
    
    
  
  
  
  
  
  
    
Custom key for this cache.
 
Class Method Summary collapse
- 
  
    
      .apply_limit(kind, seconds = nil)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Set/get time limit on data type.
 - 
  
    
      .configure(type, args = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Configure the caching approach to use.
 - 
  
    
      .default_limits  ⇒ Hash 
    
    
  
  
  
  
  
  
  
  
  
    
Default limits.
 - 
  
    
      .enable(type)  ⇒ Symbol 
    
    
  
  
  
  
  
  
  
  
  
    
Set enabled caching type.
 - 
  
    
      .redis_ping!  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Ping the redis connection and reconnect if dead.
 - 
  
    
      .type  ⇒ Symbol 
    
    
  
  
  
  
  
  
  
  
  
    
Type of caching enabled.
 
Instance Method Summary collapse
- 
  
    
      #[](name)  ⇒ Object, NilClass 
    
    
  
  
  
  
  
  
  
  
  
    
Fetch data.
 - 
  
    
      #[]=(key, val)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Set data.
 - 
  
    
      #apply_limit(kind, seconds = nil)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Apply time limit for data type.
 - 
  
    
      #clear!(*args)  ⇒ TrueClass 
    
    
  
  
  
  
  
  
  
  
  
    
Clear data.
 - 
  
    
      #get_local_storage(data_type, full_name, args = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Fetch item from local storage.
 - 
  
    
      #get_redis_storage(data_type, full_name, args = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Fetch item from redis storage.
 - 
  
    
      #get_storage(store_type, data_type, name, args = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Fetch item from storage.
 - 
  
    
      #init(name, kind, args = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Initialize a new data type.
 - 
  
    
      #initialize(key)  ⇒ Cache 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    
Create new instance.
 - 
  
    
      #internal_lock  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Execute block within internal lock.
 - 
  
    
      #locked_action(lock_name, raise_on_locked = false)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Perform action within lock.
 - 
  
    
      #registry  ⇒ Hash 
    
    
  
  
  
  
  
  
  
  
  
    
Data registry.
 - 
  
    
      #time_check_allow?(key, stamp)  ⇒ TrueClass, FalseClass 
    
    
  
  
  
  
  
  
  
  
  
    
Check if cache time has expired.
 
Constructor Details
#initialize(key) ⇒ Cache
Create new instance
      79 80 81 82 83 84 85 86  | 
    
      # File 'lib/sfn/cache.rb', line 79 def initialize(key) if key.respond_to?(:sort) key = key.flatten if key.respond_to?(:flatten) key = key.map(&:to_s).sort end @key = Digest::SHA256.hexdigest(key.to_s) @apply_limit = self.class.default_limits end  | 
  
Instance Attribute Details
#key ⇒ String (readonly)
Returns custom key for this cache
      74 75 76  | 
    
      # File 'lib/sfn/cache.rb', line 74 def key @key end  | 
  
Class Method Details
.apply_limit(kind, seconds = nil) ⇒ Object
Set/get time limit on data type
return [Integer] seconds
      51 52 53 54 55 56 57  | 
    
      # File 'lib/sfn/cache.rb', line 51 def apply_limit(kind, seconds = nil) @apply_limit ||= {} if seconds @apply_limit[kind.to_sym] = seconds.to_i end @apply_limit[kind.to_sym].to_i end  | 
  
.configure(type, args = {}) ⇒ Object
Configure the caching approach to use
      14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  | 
    
      # File 'lib/sfn/cache.rb', line 14 def configure(type, args = {}) type = type.to_sym case type when :redis begin require "redis-objects" rescue LoadError $stderr.puts "The `redis-objects` gem is required for Cache support!" raise end @_pid = Process.pid Redis::Objects.redis = Redis.new(args) when :local else raise TypeError.new("Unsupported caching type: #{type}") end enable(type) end  | 
  
.default_limits ⇒ Hash
Returns default limits
      60 61 62  | 
    
      # File 'lib/sfn/cache.rb', line 60 def default_limits (@apply_limit || {}).dup end  | 
  
.enable(type) ⇒ Symbol
Set enabled caching type
      37 38 39  | 
    
      # File 'lib/sfn/cache.rb', line 37 def enable(type) @type = type.to_sym end  | 
  
.redis_ping! ⇒ Object
Ping the redis connection and reconnect if dead
      65 66 67 68 69 70  | 
    
      # File 'lib/sfn/cache.rb', line 65 def redis_ping! if (@_pid && @_pid != Process.pid) || !Redis::Objects.redis.connected? Redis::Objects.redis.client.reconnect @_pid = Process.pid end end  | 
  
.type ⇒ Symbol
Returns type of caching enabled
      42 43 44  | 
    
      # File 'lib/sfn/cache.rb', line 42 def type @type || :local end  | 
  
Instance Method Details
#[](name) ⇒ Object, NilClass
Fetch data
      216 217 218 219 220 221 222  | 
    
      # File 'lib/sfn/cache.rb', line 216 def [](name) if kind = registry[name.to_s] get_storage(self.class.type, kind, name) else nil end end  | 
  
#[]=(key, val) ⇒ Object
this will never work, thus you should never use it
Set data
      229 230 231  | 
    
      # File 'lib/sfn/cache.rb', line 229 def []=(key, val) raise "Setting backend data is not allowed" end  | 
  
#apply_limit(kind, seconds = nil) ⇒ Object
Apply time limit for data type
return [Integer]
      247 248 249 250 251 252 253  | 
    
      # File 'lib/sfn/cache.rb', line 247 def apply_limit(kind, seconds = nil) @apply_limit ||= {} if seconds @apply_limit[kind.to_sym] = seconds.to_i end @apply_limit[kind.to_sym].to_i end  | 
  
#clear!(*args) ⇒ TrueClass
clears all data if no names provided
Clear data
      108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123  | 
    
      # File 'lib/sfn/cache.rb', line 108 def clear!(*args) internal_lock do args = registry.keys if args.empty? args.each do |key| value = self[key] if value.respond_to?(:clear) value.clear elsif value.respond_to?(:value) value.value = nil end registry.delete(key) end yield if block_given? end true end  | 
  
#get_local_storage(data_type, full_name, args = {}) ⇒ Object
make proper singleton for local storage
Fetch item from local storage
      184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200  | 
    
      # File 'lib/sfn/cache.rb', line 184 def get_local_storage(data_type, full_name, args = {}) @storage ||= {} @storage[full_name] ||= case data_type.to_sym when :array [] when :hash {} when :value LocalValue.new when :lock LocalLock.new(full_name, {:expiration => 60, :timeout => 0.1}.merge(args)) when :stamped Stamped.new(full_name.sub("#{key}_", "").to_sym, get_local_storage(:value, full_name), self) else raise TypeError.new("Unsupported caching data type encountered: #{data_type}") end end  | 
  
#get_redis_storage(data_type, full_name, args = {}) ⇒ Object
Fetch item from redis storage
      159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175  | 
    
      # File 'lib/sfn/cache.rb', line 159 def get_redis_storage(data_type, full_name, args = {}) self.class.redis_ping! case data_type.to_sym when :array Redis::List.new(full_name, {:marshal => true}.merge(args)) when :hash Redis::HashKey.new(full_name) when :value Redis::Value.new(full_name, {:marshal => true}.merge(args)) when :lock Redis::Lock.new(full_name, {:expiration => 60, :timeout => 0.1}.merge(args)) when :stamped Stamped.new(full_name.sub("#{key}_", "").to_sym, get_redis_storage(:value, full_name), self) else raise TypeError.new("Unsupported caching data type encountered: #{data_type}") end end  | 
  
#get_storage(store_type, data_type, name, args = {}) ⇒ Object
Fetch item from storage
      132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151  | 
    
      # File 'lib/sfn/cache.rb', line 132 def get_storage(store_type, data_type, name, args = {}) full_name = "#{key}_#{name}" result = nil case store_type.to_sym when :redis result = get_redis_storage(data_type, full_name.to_s, args) when :local @_local_cache ||= {} unless @_local_cache[full_name.to_s] @_local_cache[full_name.to_s] = get_local_storage(data_type, full_name.to_s, args) end result = @_local_cache[full_name.to_s] else raise TypeError.new("Unsupported caching storage type encountered: #{store_type}") end unless full_name == "#{key}_registry_#{key}" registry[name.to_s] = data_type end result end  | 
  
#init(name, kind, args = {}) ⇒ Object
Initialize a new data type
      93 94 95 96  | 
    
      # File 'lib/sfn/cache.rb', line 93 def init(name, kind, args = {}) get_storage(self.class.type, kind, name, args) true end  | 
  
#internal_lock ⇒ Object
for internal use
Execute block within internal lock
      206 207 208 209 210  | 
    
      # File 'lib/sfn/cache.rb', line 206 def internal_lock get_storage(self.class.type, :lock, :internal_access, :timeout => 20, :expiration => 120).lock do yield end end  | 
  
#locked_action(lock_name, raise_on_locked = false) ⇒ Object
Perform action within lock
      260 261 262 263 264 265 266 267 268 269 270 271 272  | 
    
      # File 'lib/sfn/cache.rb', line 260 def locked_action(lock_name, raise_on_locked = false) begin self[lock_name].lock do yield end rescue => e if e.class.to_s.end_with?("Timeout") raise if raise_on_locked else raise end end end  | 
  
#registry ⇒ Hash
Returns data registry
      99 100 101  | 
    
      # File 'lib/sfn/cache.rb', line 99 def registry get_storage(self.class.type, :hash, "registry_#{key}") end  | 
  
#time_check_allow?(key, stamp) ⇒ TrueClass, FalseClass
Check if cache time has expired
      238 239 240  | 
    
      # File 'lib/sfn/cache.rb', line 238 def time_check_allow?(key, stamp) Time.now.to_i - stamp.to_i > apply_limit(key) end  |