Class: HTM::QueryCache

Inherits:
Object
  • Object
show all
Defined in:
lib/htm/query_cache.rb

Overview

Thread-safe query result cache with TTL and statistics

Provides LRU caching for expensive query results with:

  • Configurable size and TTL

  • Thread-safe statistics tracking

  • Fast cache key generation (using Ruby’s built-in hash)

  • Selective cache invalidation by method type

Examples:

Create a cache

cache = HTM::QueryCache.new(size: 1000, ttl: 300)

Use the cache

result = cache.fetch(:search, timeframe, query, limit) do
  expensive_search_operation
end

Check statistics

cache.stats
# => { hits: 42, misses: 10, hit_rate: 80.77, size: 52 }

Selective invalidation

cache.invalidate_methods!(:search, :hybrid)  # Only invalidate search-related entries

Constant Summary collapse

METHOD_PREFIX =

Cache key prefix for method-based invalidation

"m:"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(size: 1000, ttl: 300) ⇒ QueryCache

Initialize a new query cache

Parameters:

  • size (Integer) (defaults to: 1000)

    Maximum number of entries (default: 1000, use 0 to disable)

  • ttl (Integer) (defaults to: 300)

    Time-to-live in seconds (default: 300)



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

def initialize(size: 1000, ttl: 300)
  @enabled = size.positive?

  return unless @enabled
  @cache = LruRedux::TTL::ThreadSafeCache.new(size, ttl)
  @hits = 0
  @misses = 0
  @mutex = Mutex.new
  # Track keys by method for selective invalidation
  @keys_by_method = Hash.new { |h, k| h[k] = Set.new }
end

Instance Attribute Details

#enabledObject (readonly)

Returns the value of attribute enabled.



30
31
32
# File 'lib/htm/query_cache.rb', line 30

def enabled
  @enabled
end

Instance Method Details

#clear!void

This method returns an undefined value.

Clear all cached entries



85
86
87
88
89
90
# File 'lib/htm/query_cache.rb', line 85

def clear!
  return unless @enabled

  @cache.clear
  @mutex.synchronize { @keys_by_method.clear }
end

#enabled?Boolean

Check if cache is enabled

Returns:

  • (Boolean)


146
147
148
# File 'lib/htm/query_cache.rb', line 146

def enabled?
  @enabled
end

#fetch(method) { ... } ⇒ Object

Fetch a value from cache or execute block

Parameters:

  • method (Symbol)

    Method name for cache key

  • args (Array)

    Arguments for cache key

Yields:

  • Block that computes the value if not cached

Returns:

  • (Object)

    Cached or computed value



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/htm/query_cache.rb', line 59

def fetch(method, *, &)
  return yield unless @enabled

  key = cache_key(method, *)

  if (cached = @cache[key])
    @mutex.synchronize { @hits += 1 }
    HTM::Telemetry.cache_operations.add(1, attributes: { 'operation' => 'hit' })
    return cached
  end

  @mutex.synchronize { @misses += 1 }
  HTM::Telemetry.cache_operations.add(1, attributes: { 'operation' => 'miss' })
  result = yield
  @cache[key] = result

  # Track key for selective invalidation
  @mutex.synchronize { @keys_by_method[method] << key }

  result
end

#invalidate!void

This method returns an undefined value.

Invalidate cache (alias for clear!)



96
97
98
# File 'lib/htm/query_cache.rb', line 96

def invalidate!
  clear!
end

#invalidate_methods!(*methods) ⇒ Integer

Invalidate cache entries for specific methods only

More efficient than full invalidation when only certain types of cached data need to be refreshed.

Parameters:

  • methods (Array<Symbol>)

    Method names to invalidate

Returns:

  • (Integer)

    Number of entries invalidated



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/htm/query_cache.rb', line 108

def invalidate_methods!(*methods)
  return 0 unless @enabled

  count = 0
  @mutex.synchronize do
    methods.each do |method|
      keys = @keys_by_method.delete(method) || Set.new
      keys.each do |key|
        @cache.delete(key)
        count += 1
      end
    end
  end
  count
end

#statsHash?

Get cache statistics

Returns:

  • (Hash, nil)

    Statistics hash or nil if disabled



128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/htm/query_cache.rb', line 128

def stats
  return nil unless @enabled

  total = @hits + @misses
  hit_rate = total.positive? ? (@hits.to_f / total * 100).round(2) : 0.0

  {
    hits: @hits,
    misses: @misses,
    hit_rate: hit_rate,
    size: @cache.count
  }
end