Module: IdentityCache

Defined in:
lib/identity_cache.rb,
lib/identity_cache/version.rb,
lib/identity_cache/query_api.rb,
lib/identity_cache/configuration_dsl.rb,
lib/identity_cache/belongs_to_caching.rb,
lib/identity_cache/cache_key_generation.rb,
lib/identity_cache/memoized_cache_proxy.rb,
lib/identity_cache/parent_model_expiration.rb

Defined Under Namespace

Modules: BelongsToCaching, CacheKeyGeneration, ConfigurationDSL, ParentModelExpiration, QueryAPI Classes: AlreadyIncludedError, InverseAssociationError, MemoizedCacheProxy

Constant Summary collapse

CACHED_NIL =
:idc_cached_nil
VERSION =
"0.0.3"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.cacheObject (readonly)

Returns the value of attribute cache.



24
25
26
# File 'lib/identity_cache.rb', line 24

def cache
  @cache
end

.loggerObject

Returns the value of attribute logger.



23
24
25
# File 'lib/identity_cache.rb', line 23

def logger
  @logger
end

.readonlyObject

Returns the value of attribute readonly.



23
24
25
# File 'lib/identity_cache.rb', line 23

def readonly
  @readonly
end

Class Method Details

.cache_backend=(cache_adaptor) ⇒ Object

Sets the cache adaptor IdentityCache will be using

Parameters

cache_adaptor - A ActiveSupport::Cache::Store



32
33
34
# File 'lib/identity_cache.rb', line 32

def cache_backend=(cache_adaptor)
  cache.memcache = cache_adaptor
end

.denormalized_schema_hash(klass) ⇒ Object



121
122
123
124
125
126
127
128
129
130
# File 'lib/identity_cache.rb', line 121

def denormalized_schema_hash(klass)
  schema_string = schema_to_string(klass.columns)
  if klass.respond_to?(:all_cached_associations_needing_population) && !(embeded_associations = klass.all_cached_associations_needing_population).empty?
    embedded_schema = embeded_associations.map do |name, options|
      "#{name}:(#{denormalized_schema_hash(options[:association_class])})"
    end.sort.join(',')
    schema_string << "," << embedded_schema
  end
  IdentityCache.memcache_hash(schema_string)
end

.fetch(key, &block) ⇒ Object

Cache retrieval and miss resolver primitive; given a key it will try to retrieve the associated value from the cache otherwise it will return the value of the execution of the block.

Parameters

key A cache key string



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/identity_cache.rb', line 55

def fetch(key, &block)
  result = cache.read(key) if should_cache?

  if result.nil?
    if block_given?
      result = yield
      result = map_cached_nil_for(result)

      if should_cache?
        cache.write(key, result)
      end
    end
  end

  unmap_cached_nil_for(result)
end

.fetch_multi(*keys, &block) ⇒ Object

Same as fetch, except that it will try a collection of keys, using the multiget operation of the cache adaptor

Parameters

keys A collection of key strings



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/identity_cache.rb', line 86

def fetch_multi(*keys, &block)
  return {} if keys.size == 0
  result = {}
  result = cache.read_multi(*keys) if should_cache?

  hit_keys = result.select {|key, value| value.present? }.keys
  missed_keys = keys - hit_keys

  if missed_keys.size > 0
    if block_given?
      replacement_results = nil
      replacement_results = yield missed_keys
      missed_keys.zip(replacement_results) do |(key, replacement_result)|
        if should_cache?
          replacement_result  = map_cached_nil_for(replacement_result )
          cache.write(key, replacement_result)
          logger.debug { "[IdentityCache] cache miss for #{key} (multi)" }
        end
        result[key] = replacement_result
      end
    end
  end


  result.keys.each do |key|
    result[key] = unmap_cached_nil_for(result[key])
  end

  result
end

.included(base) ⇒ Object

:nodoc:



132
133
134
135
136
137
138
139
140
# File 'lib/identity_cache.rb', line 132

def included(base) #:nodoc:
  raise AlreadyIncludedError if base.respond_to? :cache_indexes

  base.send(:include, ArTransactionChanges) unless base.include?(ArTransactionChanges)
  base.send(:include, IdentityCache::BelongsToCaching)
  base.send(:include, IdentityCache::CacheKeyGeneration)
  base.send(:include, IdentityCache::ConfigurationDSL)
  base.send(:include, IdentityCache::QueryAPI)
end

.map_cached_nil_for(value) ⇒ Object



72
73
74
# File 'lib/identity_cache.rb', line 72

def map_cached_nil_for(value)
  value.nil? ? IdentityCache::CACHED_NIL : value
end

.memcache_hash(key) ⇒ Object

:nodoc:



142
143
144
# File 'lib/identity_cache.rb', line 142

def memcache_hash(key) #:nodoc:
  CityHash.hash64(key)
end

.schema_to_string(columns) ⇒ Object



117
118
119
# File 'lib/identity_cache.rb', line 117

def schema_to_string(columns)
  columns.sort_by(&:name).map{|c| "#{c.name}:#{c.type}"}.join(',')
end

.should_cache?Boolean

:nodoc:

Returns:

  • (Boolean)


44
45
46
# File 'lib/identity_cache.rb', line 44

def should_cache? # :nodoc:
  !readonly && ActiveRecord::Base.connection.open_transactions == 0
end

.unmap_cached_nil_for(value) ⇒ Object



77
78
79
# File 'lib/identity_cache.rb', line 77

def unmap_cached_nil_for(value)
  value == IdentityCache::CACHED_NIL ? nil : value
end