Struct.new(:max_total, :max_value, :max_count, :expiration, :hook, :objs, :total_size, :list, :hits, :misses)
A Hash-alike LRU cache that provides fine-grained control over content restrictions.
It allows you to set:
a maximum number of elements
the maximum amount of memory used for all elements
the allowed memory-size per element
time to live
Differences to the original implementation include:
Note that due to calculating object size with Marshal, you might have to do some evaluation as to how large your values will be when marshaled, for example a String will have String#size + 10. This differs from object to object and between versions of Marshal, so be generous.
Copyright (C) 2002 Yoshinori K. Okuji
You may redistribute it and/or modify it under the same terms as Ruby.
On 1.8 we raise IndexError, on 1.9 we raise KeyError
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 34 34: def initialize(options = {}, &hook) 35: self.max_value = options[:max_value] 36: self.max_total = options[:max_total] 37: self.max_count = options[:max_count] 38: self.expiration = options[:expiration] 39: 40: avoid_insane_options 41: 42: self.hook = hook 43: 44: self.objs = {} 45: self.list = [] 46: 47: self.total_size = 0 48: self.hits = self.misses = 0 49: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 120 120: def [](key) 121: expire 122: 123: unless objs.key?(key) 124: self.misses += 1 125: return 126: end 127: 128: obj = objs[key] 129: obj.atime = Time.now.to_i 130: 131: list.delete_if{|list_key| key == list_key } 132: list << key 133: 134: self.hits += 1 135: obj.content 136: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 138 138: def []=(key, obj) 139: expire 140: 141: invalidate key if key?(key) 142: 143: size = Marshal.dump(obj).size 144: 145: if max_value && max_value < max_total 146: warn "%p isn't cached because it exceeds max_value %p" % [obj, max_value] 147: return obj 148: end 149: 150: if max_value.nil? && max_total && max_total < size 151: warn "%p isn't cached because it exceeds max_total: %p" % [obj, max_total] 152: return obj 153: end 154: 155: invalidate list.first if max_count && max_count == list.size 156: 157: self.total_size += size 158: 159: if max_total 160: invalidate list.first until total_size < max_total 161: end 162: 163: objs[key] = CacheObject.new(obj, size, Time.now.to_i) 164: list << key 165: 166: obj 167: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 102 102: def clear 103: objs.each{|key, obj| hook.call(key, obj) } if hook 104: objs.clear 105: list.clear 106: self.total_size = 0 107: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 88 88: def delete(key) 89: return unless objs.key?(key) 90: obj = objs[key] 91: 92: hook.call(key, obj.content) if hook 93: self.total_size -= obj.size 94: objs.delete key 95: 96: list.delete_if{|list_key| key == list_key } 97: 98: obj.content 99: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 179 179: def each_key(&block) 180: return enum_for(:each_key) unless block_given? 181: objs.each_key{|key| yield key } 182: self 183: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 173 173: def each_pair 174: return enum_for(:each_pair) unless block_given? 175: objs.each{|key, obj| yield key, obj.content } 176: self 177: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 185 185: def each_value 186: return enum_for(:each_value) unless block_given? 187: objs.each_value{|obj| yield obj.content } 188: self 189: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 191 191: def empty? 192: objs.empty? 193: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 110 110: def expire 111: return unless expiration 112: now = Time.now.to_i 113: 114: list.each_with_index do |key, index| 115: break unless (objs[key].atime + expiration) <= now 116: invalidate key 117: end 118: end
Note that this method diverges from the default behaviour of the Ruby Hash. If the cache doesn’t find content for the given key, it will store the given default instead. Optionally it also takes a block, the return value of the block is then stored and returned.
@example
lru = LRUHash.new lru.fetch(:a) # => KeyError: key not found: :a lru.fetch(:a, :b) # => :b lru.fetch(:a) # => :b lru.fetch(:c){|key| key.to_s } # => 'c' lru.fetch(:c) # => 'c'
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 208 208: def fetch(key, default = (p_default = true; nil)) 209: if key?(key) 210: value = self[key] 211: elsif p_default.nil? 212: value = self[key] = default 213: elsif block_given? 214: value = self[key] = yield(key) 215: else 216: raise KeyError, "key not found: %p" % [key] 217: end 218: 219: value 220: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 63 63: def index(given_value) 64: objs.each do |key, obj| 65: return key if given_value == obj.content 66: end 67: 68: nil 69: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 51 51: def key?(key) 52: objs.key?(key) 53: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 71 71: def keys 72: objs.keys 73: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 75 75: def size 76: objs.size 77: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 222 222: def statistics 223: {:size => total_size, :count => list.size, :hits => hits, :misses => misses} 224: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 169 169: def store(key, value) 170: self[key] = value 171: end
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 80 80: def to_hash 81: objs.dup 82: end
Sanity checks.
# File lib/ramaze/snippets/ramaze/lru_hash.rb, line 229 229: def avoid_insane_options 230: if (max_value && max_total) && max_value > max_total 231: raise ArgumentError, "max_value exceeds max_total (#{max_value} > #{max_total})" 232: end 233: if max_value && max_value <= 0 234: raise ArgumentError, "invalid max_value `#{max_value}'" 235: end 236: if max_total && max_total <= 0 237: raise ArgumentError, "invalid max_total `#{max_total}'" 238: end 239: if max_count && max_count <= 0 240: raise ArgumentError, "invalid max_count `#{max_count}'" 241: end 242: if expiration && expiration <= 0 243: raise ArgumentError, "invalid expiration `#{expiration}'" 244: end 245: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.