module MCollective::Cache

A class to manage a number of named caches. Each cache can have a unique timeout for keys in it and each cache has an independent Mutex protecting access to it.

This cache is setup early in the process of loading the mcollective libraries, before any threads are created etc making it suitable as a cross thread cache or just a store for Mutexes you need to use across threads like in an Agent or something.

# sets up a new cache, noop if it already exist
Cache.setup(:ddl, 600)
=> true

# writes an item to the :ddl cache, this item will
# be valid on the cache for 600 seconds
Cache.write(:ddl, :something, "value")
=> "value"

# reads from the cache, read failures due to non existing
# data or expired data will raise an exception
Cache.read(:ddl, :something)
=> "value"

# time left till expiry, raises if nothing is found
Cache.ttl(:ddl, :something)
=> 500

# forcibly evict something from the cache
Cache.invalidate!(:ddl, :something)
=> "value"

# deletes an entire named cache and its mutexes
Cache.delete!(:ddl)
=> true

# you can also just use this cache as a global mutex store
Cache.setup(:mylock)

Cache.synchronize(:mylock) do
  do_something()
end

Public Class Methods

delete!(cache_name) click to toggle source
   # File lib/mcollective/cache.rb
74 def self.delete!(cache_name)
75   @locks_mutex.synchronize do
76     raise("No cache called '%s'" % cache_name) unless @cache_locks.include?(cache_name)
77 
78     @cache_locks.delete(cache_name)
79     @cache.delete(cache_name)
80   end
81 
82   true
83 end
has_cache?(cache_name) click to toggle source
   # File lib/mcollective/cache.rb
68 def self.has_cache?(cache_name)
69   @locks_mutex.synchronize do
70     @cache.include?(cache_name)
71   end
72 end
invalidate!(cache_name, key) click to toggle source
    # File lib/mcollective/cache.rb
135 def self.invalidate!(cache_name, key)
136   raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
137 
138   @cache_locks[cache_name].synchronize do
139     return false unless @cache[cache_name].include?(key)
140 
141     @cache[cache_name].delete(key)
142   end
143 end
read(cache_name, key) click to toggle source
    # File lib/mcollective/cache.rb
 97 def self.read(cache_name, key)
 98   raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
 99 
100   unless ttl(cache_name, key) > 0
101     Log.debug("Cache expired on '%s' key '%s'" % [cache_name, key])
102     raise("Cache for item '%s' on cache '%s' has expired" % [key, cache_name])
103   end
104 
105   Log.debug("Cache hit on '%s' key '%s'" % [cache_name, key])
106 
107   @cache_locks[cache_name].synchronize do
108     @cache[cache_name][key][:value]
109   end
110 end
setup(cache_name, ttl=300) click to toggle source
   # File lib/mcollective/cache.rb
54 def self.setup(cache_name, ttl=300)
55   @locks_mutex.synchronize do
56     break if @cache_locks.include?(cache_name)
57 
58     @cache_locks[cache_name] = Mutex.new
59 
60     @cache_locks[cache_name].synchronize do
61       @cache[cache_name] = {:max_age => Float(ttl)}
62     end
63   end
64 
65   true
66 end
synchronize(cache_name) { || ... } click to toggle source
    # File lib/mcollective/cache.rb
125 def self.synchronize(cache_name)
126   raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
127 
128   raise ("No block supplied to synchronize") unless block_given?
129 
130   @cache_locks[cache_name].synchronize do
131     yield
132   end
133 end
ttl(cache_name, key) click to toggle source
    # File lib/mcollective/cache.rb
112 def self.ttl(cache_name, key)
113   raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
114 
115   @cache_locks[cache_name].synchronize do
116     unless @cache[cache_name].include?(key)
117       Log.debug("Cache miss on '%s' key '%s'" % [cache_name, key])
118       raise("No item called '%s' for cache '%s'" % [key, cache_name])
119     end
120 
121     @cache[cache_name][:max_age] - (Time.now - @cache[cache_name][key][:cache_create_time])
122   end
123 end
write(cache_name, key, value) click to toggle source
   # File lib/mcollective/cache.rb
85 def self.write(cache_name, key, value)
86   raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
87 
88   @cache_locks[cache_name].synchronize do
89     @cache[cache_name][key] ||= {}
90     @cache[cache_name][key][:cache_create_time] = Time.now
91     @cache[cache_name][key][:value] = value
92   end
93 
94   value
95 end