Class: LRUHash

Inherits:
Object
  • Object
show all
Defined in:
lib/semian/lru_hash.rb

Defined Under Namespace

Classes: NoopMutex

Instance Method Summary collapse

Constructor Details

#initialize(max_size: Semian.maximum_lru_size, min_time: Semian.minimum_lru_time) ⇒ LRUHash

Create an LRU hash

Arguments:

+max_size+ The maximum size of the table
+min_time+ The minimum time in seconds a resource can live in the cache

Note:

The +min_time+ is a stronger guarantee than +max_size+. That is, if there are
more than +max_size+ entries in the cache, but they've all been updated more
recently than +min_time+, the garbage collection will not remove them and the
cache can grow without bound. This usually means that you have many active
circuits to disparate endpoints (or your circuit names are bad).
If the max_size is 0, the garbage collection will be very aggressive and
potentially computationally expensive.


56
57
58
59
60
61
62
63
64
65
66
# File 'lib/semian/lru_hash.rb', line 56

def initialize(max_size: Semian.maximum_lru_size, min_time: Semian.minimum_lru_time)
  @max_size = max_size
  @min_time = min_time
  @table = {}
  @lock =
    if Semian.thread_safe?
      ::Thread::Mutex.new
    else
      ::LRUHash::NoopMutex.new
    end
end

Instance Method Details

#[](key) ⇒ Object



119
120
121
# File 'lib/semian/lru_hash.rb', line 119

def [](key)
  get(key)
end

#[]=(key, resource) ⇒ Object



115
116
117
# File 'lib/semian/lru_hash.rb', line 115

def []=(key, resource)
  set(key, resource)
end

#clearObject



38
39
40
# File 'lib/semian/lru_hash.rb', line 38

def clear
  @lock.synchronize { @table.clear }
end

#count(&block) ⇒ Object



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

def count(&block)
  @lock.synchronize { @table.count(&block) }
end

#delete(key) ⇒ Object



109
110
111
112
113
# File 'lib/semian/lru_hash.rb', line 109

def delete(key)
  @lock.synchronize do
    @table.delete(key)
  end
end

#empty?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/semian/lru_hash.rb', line 76

def empty?
  @lock.synchronize { @table.empty? }
end

#get(key) ⇒ Object

This method uses the property that “Hashes enumerate their values in the order that the corresponding keys were inserted.” Deleting a key and re-inserting it effectively moves it to the front of the cache. Update the ‘updated_at` field so we can use it later do decide if the resource is “in use”.



98
99
100
101
102
103
104
105
106
107
# File 'lib/semian/lru_hash.rb', line 98

def get(key)
  @lock.synchronize do
    found = @table.delete(key)
    if found
      @table[key] = found
      found.updated_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    end
    found
  end
end

#keysObject



34
35
36
# File 'lib/semian/lru_hash.rb', line 34

def keys
  @lock.synchronize { @table.keys }
end

#set(key, resource) ⇒ Object



84
85
86
87
88
89
90
91
# File 'lib/semian/lru_hash.rb', line 84

def set(key, resource)
  @lock.synchronize do
    @table.delete(key)
    @table[key] = resource
    resource.updated_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  end
  clear_unused_resources if @table.length > @max_size
end

#sizeObject



68
69
70
# File 'lib/semian/lru_hash.rb', line 68

def size
  @lock.synchronize { @table.size }
end

#valuesObject



80
81
82
# File 'lib/semian/lru_hash.rb', line 80

def values
  @lock.synchronize { @table.values }
end