forked from Altiscale/burstingsim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlru.rb
149 lines (110 loc) · 2.51 KB
/
lru.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
require 'set'
# Time based LRU. Keeps a 1-minute window of events and pops everything else in order to be processed.
class Lru
attr_reader :max_size, :ttl
def initialize(*args)
max_size, ttl, current_time = args
ttl ||= :none
fail ArgumentError.new(:max_size) if
max_size < 1 && max_size != -1
fail ArgumentError.new(:ttl) unless
ttl == :none || ((ttl.is_a? Numeric) && ttl >= 0)
@max_size = max_size #-1 for unlimited max size
@ttl = ttl
@data_lru = {}
@current_time = 9_999_999_999_999_999
end
def max_size=(max_size)
max_size ||= @max_size
fail ArgumentError.new(:max_size) if
max_size < 1 && max_size != -1
@max_size = max_size
resize
end
def ttl=(ttl)
ttl ||= @ttl
fail ArgumentError.new(:ttl) unless
ttl == :none || ((ttl.is_a? Numeric) && ttl >= 0)
@ttl = ttl
pop_expired_keys
end
def [](key)
found = true
value = @data_lru.delete(key) { found = false }
@data_lru[key] = value if found
end
def []=(key, val)
@data_lru.delete(key)
@data_lru[key] = val
unless @max_size == -1
if @data_lru.size > @max_size
key, = @data_lru.first
@data_lru.delete(key)
end
end
val
end
def print
array = @data_lru.to_a
array.reverse!.each do |k, v|
puts "#{k.inspect} => #{v}"
end
end
def each
array = @data_lru.to_a
array.reverse!.each do |pair|
yield pair
end
end
# used further up the chain, non thread safe each
alias_method :each_unsafe, :each
def to_a
array = @data_lru.to_a
array.reverse!
end
def delete(key)
@data_lru.delete(key)
end
alias_method :evict, :delete
def key?(key)
@data_lru.key?(key)
end
alias_method :has_key?, :key?
def clear
@data_lru.clear
end
def expire(timestamp)
@current_time = timestamp
pop_expired_keys
end
def count
@data_lru.size
end
def empty?
@data_lru.empty?
end
protected
def pop_expired_keys
return if @ttl == :none || @data_lru.empty?
ttl_horizon = @current_time - @ttl
key, time = @data_lru.first
return unless time < ttl_horizon
s = Set.new {}
until time.nil? || time >= ttl_horizon
@data_lru.delete(key)
s.add(key)
key, time = @data_lru.first
end
s
end
def resize
s = pop_expired_keys
unless @max_size == -1
while @data_lru.size > @max_size
key, = @data_lru.first
@data_lru.delete(key)
end
end
s
end
end