Class: Ipregistry::Cache::Memory

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

Overview

A thread-safe, in-process cache with time-based expiration and a bounded size using least-recently-used eviction.

cache = Ipregistry::Cache::Memory.new(max_size: 8192, ttl: 600)
client = Ipregistry::Client.new("YOUR_API_KEY", cache: cache)

Constant Summary collapse

DEFAULT_MAX_SIZE =
4096
DEFAULT_TTL =

seconds

600

Instance Method Summary collapse

Constructor Details

#initialize(max_size: DEFAULT_MAX_SIZE, ttl: DEFAULT_TTL, clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }) ⇒ Memory

Returns a new instance of Memory.

Parameters:

  • max_size (Integer) (defaults to: DEFAULT_MAX_SIZE)

    maximum number of entries held before the least recently used entry is evicted (default 4096)

  • ttl (Numeric) (defaults to: DEFAULT_TTL)

    how long, in seconds, an entry stays valid after being written (default 600)

  • clock (#call) (defaults to: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) })

    overridable monotonic clock, for testing

Raises:

  • (ArgumentError)


40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ipregistry/cache.rb', line 40

def initialize(max_size: DEFAULT_MAX_SIZE, ttl: DEFAULT_TTL,
               clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) })
  raise ArgumentError, "max_size must be positive" unless max_size.positive?
  raise ArgumentError, "ttl must be positive" unless ttl.positive?

  @max_size = max_size
  @ttl = ttl
  @clock = clock
  @mutex = Mutex.new
  @entries = {} # key => [value, expires_at]; insertion order tracks recency
end

Instance Method Details

#clearObject

Removes every entry.



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

def clear
  @mutex.synchronize { @entries.clear }
  nil
end

#delete(key) ⇒ Object

Removes the entry for key, if present.



82
83
84
85
# File 'lib/ipregistry/cache.rb', line 82

def delete(key)
  @mutex.synchronize { @entries.delete(key) }
  nil
end

#get(key) ⇒ Object

Returns the cached value for key, or nil when absent or expired.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ipregistry/cache.rb', line 53

def get(key)
  @mutex.synchronize do
    value, expires_at = @entries[key]
    next nil unless expires_at

    if @clock.call > expires_at
      @entries.delete(key)
      next nil
    end

    # Re-insert to mark the entry as most recently used.
    @entries.delete(key)
    @entries[key] = [value, expires_at]
    value
  end
end

#set(key, value) ⇒ Object

Stores value under key, refreshing its expiration and evicting the least recently used entry if the cache is full.



72
73
74
75
76
77
78
79
# File 'lib/ipregistry/cache.rb', line 72

def set(key, value)
  @mutex.synchronize do
    @entries.delete(key)
    @entries[key] = [value, @clock.call + @ttl]
    @entries.delete(@entries.each_key.first) while @entries.size > @max_size
  end
  nil
end

#sizeObject

Current number of entries, including possibly stale ones. Primarily useful in tests.



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

def size
  @mutex.synchronize { @entries.size }
end