Class: Lutaml::Store::CacheStore

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/store/cache_store.rb

Overview

TTL-aware cache store with LRU eviction. Wraps a storage adapter directly.

Defined Under Namespace

Classes: CacheEntry

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ CacheStore

Returns a new instance of CacheStore.



53
54
55
56
57
58
59
60
# File 'lib/lutaml/store/cache_store.rb', line 53

def initialize(config = {})
  @adapter = create_adapter(config)
  @default_ttl = config[:default_ttl]
  @max_size = config[:max_size]
  @cleanup_interval = config[:cleanup_interval] || 300
  @last_cleanup = Time.now
  @access_times = {}
end

Instance Attribute Details

#adapterObject (readonly)

Returns the value of attribute adapter.



51
52
53
# File 'lib/lutaml/store/cache_store.rb', line 51

def adapter
  @adapter
end

Instance Method Details

#cache_infoObject



189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/lutaml/store/cache_store.rb', line 189

def cache_info
  total_keys = @adapter.keys.size
  valid_keys = keys.size
  expired_keys = total_keys - valid_keys

  {
    total_entries: total_keys,
    valid_entries: valid_keys,
    expired_entries: expired_keys,
    max_size: @max_size,
    default_ttl: @default_ttl,
    last_cleanup: @last_cleanup
  }
end

#cleanup_expiredObject



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/lutaml/store/cache_store.rb', line 170

def cleanup_expired
  expired_keys = []

  @adapter.each_key do |key|
    entry_data = @adapter.get(key)
    next unless entry_data

    entry = deserialize_entry(entry_data)
    expired_keys << key if entry.expired?
  rescue StandardError
    expired_keys << key
  end

  expired_keys.each { |key| delete(key) }
  @last_cleanup = Time.now

  expired_keys.size
end

#clearObject



117
118
119
120
# File 'lib/lutaml/store/cache_store.rb', line 117

def clear
  @access_times.clear
  @adapter.clear
end

#closeObject



236
237
238
# File 'lib/lutaml/store/cache_store.rb', line 236

def close
  @adapter.close
end

#delete(key) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/lutaml/store/cache_store.rb', line 98

def delete(key)
  value = nil
  entry_data = @adapter.get(key)
  if entry_data
    begin
      entry = deserialize_entry(entry_data)
      value = entry.value unless entry.expired?
    rescue StandardError
      # If we can't deserialize, treat as nil
    end
  end

  @access_times.delete(key)

  deleted = @adapter.delete(key)

  deleted ? value : nil
end

#exists?(key) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/lutaml/store/cache_store.rb', line 122

def exists?(key)
  return false unless @adapter.exists?(key)

  entry_data = @adapter.get(key)
  return false unless entry_data

  begin
    entry = deserialize_entry(entry_data)
    !entry.expired?
  rescue StandardError
    false
  end
end

#expire(key) ⇒ Object



162
163
164
# File 'lib/lutaml/store/cache_store.rb', line 162

def expire(key)
  delete(key)
end

#expire_allObject



166
167
168
# File 'lib/lutaml/store/cache_store.rb', line 166

def expire_all
  clear
end

#fetch(key, ttl: :default, metadata: {}, &block) ⇒ Object



225
226
227
228
229
230
231
232
233
234
# File 'lib/lutaml/store/cache_store.rb', line 225

def fetch(key, ttl: :default, metadata: {}, &block)
  value = get(key)
  return value unless value.nil?

  return nil unless block_given?

  value = block.call
  set(key, value, ttl: ttl, metadata: )
  value
end

#get(key) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/lutaml/store/cache_store.rb', line 62

def get(key)
  cleanup_expired if should_cleanup?

  entry_data = @adapter.get(key)
  return nil unless entry_data

  begin
    entry = deserialize_entry(entry_data)

    if entry.expired?
      delete(key)
      return nil
    end

    @access_times[key] = Time.now
    entry.value
  rescue StandardError
    delete(key)
    nil
  end
end

#keysObject



136
137
138
139
# File 'lib/lutaml/store/cache_store.rb', line 136

def keys
  cleanup_expired if should_cleanup?
  @adapter.keys.select { |key| exists?(key) }
end

#set(key, value, ttl: :default, metadata: {}) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/lutaml/store/cache_store.rb', line 84

def set(key, value, ttl: :default, metadata: {})
  cleanup_expired if should_cleanup?
  evict_if_needed

  effective_ttl = ttl == :default ? @default_ttl : ttl
  entry = CacheEntry.new(value, ttl: effective_ttl, metadata: )

  serialized_entry = serialize_entry(entry)
  @adapter.set(key, serialized_entry)

  @access_times[key] = Time.now
  value
end

#sizeObject



141
142
143
144
# File 'lib/lutaml/store/cache_store.rb', line 141

def size
  cleanup_expired if should_cleanup?
  keys.size
end

#touch(key, ttl: nil) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/lutaml/store/cache_store.rb', line 204

def touch(key, ttl: nil)
  entry_data = @adapter.get(key)
  return false unless entry_data

  begin
    entry = deserialize_entry(entry_data)
    return false if entry.expired?

    new_ttl = ttl || entry.ttl
    new_entry = CacheEntry.new(entry.value, ttl: new_ttl, metadata: entry.)

    serialized_entry = serialize_entry(new_entry)
    @adapter.set(key, serialized_entry)

    @access_times[key] = Time.now
    true
  rescue StandardError
    false
  end
end

#ttl(key) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/lutaml/store/cache_store.rb', line 146

def ttl(key)
  entry_data = @adapter.get(key)
  return nil unless entry_data

  begin
    entry = deserialize_entry(entry_data)
    return nil if entry.expired?
    return nil unless entry.ttl

    remaining = entry.ttl - (Time.now - entry.created_at)
    remaining.positive? ? remaining : nil
  rescue StandardError
    nil
  end
end