Class: Cache

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/cache.rb

Overview

Cache manager based on the LRU algorithm.

Defined Under Namespace

Classes: CACHE_OBJECT

Constant Summary collapse

CACHE_VERSION =
'0.3'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, &hook) ⇒ Cache

initialize(max_obj_size = nil, max_size = nil, max_num = nil,

expiration = nil, &hook)

initialize(hash, &hook)



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/cache.rb', line 22

def initialize(*args, &hook)
  if args.size == 1 and args[0].kind_of?(Hash)
    @max_obj_size = @max_size = @max_num = @expiration = nil
    args[0].each do |k, v|
	k = k.intern if k.respond_to?(:intern)
	case k
	when :max_obj_size
 @max_obj_size = v
	when :max_size
 @max_size = v
	when :max_num
 @max_num = v
	when :expiration
 @expiration = v
	end
    end
  else
    @max_obj_size, @max_size, @max_num, @expiration = args
  end

  # Sanity checks.
  if @max_obj_size and @max_size and @max_obj_size > @max_size
    raise ArgumentError, "max_obj_size exceeds max_size (#{@max_obj_size} > #{@max_size})"
  end
  if @max_obj_size and @max_obj_size <= 0
    raise ArgumentError, "invalid max_obj_size `#{@max_obj_size}'"
  end
  if @max_size and @max_size <= 0
    raise ArgumentError, "invalid max_size `#{@max_size}'"
  end
  if @max_num and @max_num <= 0
    raise ArgumentError, "invalid max_num `#{@max_num}'"
  end
  if @expiration and @expiration <= 0
    raise ArgumentError, "invalid expiration `#{@expiration}'"
  end
  
  @hook = hook
  
  @objs = {}
  @size = 0
  @list = []
  
  @hits = 0
  @misses = 0
end

Instance Attribute Details

#expirationObject (readonly)

Returns the value of attribute expiration.



69
70
71
# File 'lib/cache.rb', line 69

def expiration
  @expiration
end

#max_numObject (readonly)

Returns the value of attribute max_num.



69
70
71
# File 'lib/cache.rb', line 69

def max_num
  @max_num
end

#max_obj_sizeObject (readonly)

Returns the value of attribute max_obj_size.



69
70
71
# File 'lib/cache.rb', line 69

def max_obj_size
  @max_obj_size
end

#max_sizeObject (readonly)

Returns the value of attribute max_size.



69
70
71
# File 'lib/cache.rb', line 69

def max_size
  @max_size
end

Class Method Details

.versionObject



15
16
17
# File 'lib/cache.rb', line 15

def self.version
  CACHE_VERSION
end

Instance Method Details

#[](key) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/cache.rb', line 159

def [](key)
  self.expire()
  
  unless @objs.include?(key)
    @misses += 1
    return nil
  end
  
  obj = @objs[key]
  obj.atime = Time.now.to_i

  @list.each_index do |i|
    if @list[i] == key
	@list.delete_at(i)
	break
    end
  end
  @list.push(key)

  @hits += 1
  obj.content
end

#[]=(key, obj) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/cache.rb', line 182

def []=(key, obj)
  self.expire()
  
  if self.cached?(key)
    self.invalidate(key)
  end

  size = obj.to_s.size
  if @max_obj_size and @max_obj_size < size
    if $DEBUG
	$stderr.puts("warning: `#{obj.inspect}' isn't cached because its size exceeds #{@max_obj_size}")
    end
    return obj
  end
  if @max_obj_size.nil? and @max_size and @max_size < size
    if $DEBUG
	$stderr.puts("warning: `#{obj.inspect}' isn't cached because its size exceeds #{@max_size}")
    end
    return obj
  end
    
  if @max_num and @max_num == @list.size
    self.invalidate(@list.first)
  end

  @size += size
  if @max_size
    while @max_size < @size
	self.invalidate(@list.first)
    end
  end

  @objs[key] = CACHE_OBJECT.new(obj, size, Time.now.to_i)
  @list.push(key)

  obj
end

#cached?(key) ⇒ Boolean Also known as: include?, member?, key?, has_key?

Returns:

  • (Boolean)


71
72
73
# File 'lib/cache.rb', line 71

def cached?(key)
  @objs.include?(key)
end

#cached_value?(val) ⇒ Boolean Also known as: has_value?, value?

Returns:

  • (Boolean)


79
80
81
82
83
84
# File 'lib/cache.rb', line 79

def cached_value?(val)
  self.each_value do |v|
    return true if v == val
  end
  false
end

#each_keyObject



232
233
234
235
236
237
# File 'lib/cache.rb', line 232

def each_key
  @objs.each_key do |key|
    yield key
  end
  self
end

#each_pairObject Also known as: each



224
225
226
227
228
229
# File 'lib/cache.rb', line 224

def each_pair
  @objs.each do |key, obj|
    yield key, obj.content
  end
  self
end

#each_valueObject



239
240
241
242
243
244
# File 'lib/cache.rb', line 239

def each_value
  @objs.each_value do |obj|
    yield obj.content
  end
  self
end

#empty?Boolean

Returns:

  • (Boolean)


246
247
248
# File 'lib/cache.rb', line 246

def empty?
  @objs.empty?
end

#expireObject



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/cache.rb', line 146

def expire()
  if @expiration
    now = Time.now.to_i
    @list.each_index do |i|
	key = @list[i]
	
	break unless @objs[key].atime + @expiration <= now
	self.invalidate(key)
    end
  end
#    GC.start
end

#fetch(key, default = nil) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/cache.rb', line 250

def fetch(key, default = nil)
  val = self[key]
  if val.nil?
    if default
	val = self[key] = default
    elsif block_given?
	val = self[key] = yield(key)
    else
	raise IndexError, "invalid key `#{key}'"
    end
  end
  val
end

#index(val) ⇒ Object



88
89
90
91
92
93
# File 'lib/cache.rb', line 88

def index(val)
  self.each_pair do |k,v|
    return k if v == val
  end
  nil
end

#invalidate(key) ⇒ Object Also known as: delete



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/cache.rb', line 112

def invalidate(key)
  obj = @objs[key]
  if obj
    if @hook
	@hook.call(key, obj.content)
    end
    @size -= obj.size
    @objs.delete(key)
    @list.each_index do |i|
	if @list[i] == key
 @list.delete_at(i)
 break
	end
    end
  elsif block_given?
    return yield(key)
  end
  obj.content
end

#invalidate_allObject Also known as: clear



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/cache.rb', line 133

def invalidate_all()
  if @hook
    @objs.each do |key, obj|
	@hook.call(key, obj)
    end
  end

  @objs.clear
  @list.clear
  @size = 0
end

#keysObject



95
96
97
# File 'lib/cache.rb', line 95

def keys
  @objs.keys
end

#lengthObject Also known as: size



99
100
101
# File 'lib/cache.rb', line 99

def length
  @objs.length
end

#statisticsObject

The total size of cached objects, the number of cached objects, the number of cache hits, and the number of cache misses.



266
267
268
# File 'lib/cache.rb', line 266

def statistics()
  [@size, @list.size, @hits, @misses]
end

#store(key, value) ⇒ Object



220
221
222
# File 'lib/cache.rb', line 220

def store(key, value)
  self[key] = value
end

#to_hashObject



104
105
106
# File 'lib/cache.rb', line 104

def to_hash
  @objs.dup
end

#valuesObject



108
109
110
# File 'lib/cache.rb', line 108

def values
  @objs.collect {|key, obj| obj.content}
end