Class: Magick::AuditLog::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/magick/audit_log.rb

Overview

Durable, shared audit storage layered on the adapter registry. Entries live under a reserved pseudo-feature namespace, one capped list per feature, so feature reads never drag audit history along and deleting a feature does not destroy the record of who changed it.

Constant Summary collapse

ENTRIES_KEY =
'entries'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registry, retention:) ⇒ Store

Returns a new instance of Store.



132
133
134
135
# File 'lib/magick/audit_log.rb', line 132

def initialize(registry, retention:)
  @registry = registry
  @retention = retention
end

Instance Attribute Details

#registry ⇒ Object (readonly)

Returns the value of attribute registry.



130
131
132
# File 'lib/magick/audit_log.rb', line 130

def registry
  @registry
end

#retention ⇒ Object (readonly)

Returns the value of attribute retention.



130
131
132
# File 'lib/magick/audit_log.rb', line 130

def retention
  @retention
end

Instance Method Details

#durable? ⇒ Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/magick/audit_log.rb', line 137

def durable?
  !durable_adapters.empty?
end

#read(feature_name) ⇒ Object

Read straight from the shared adapters — never through the registry, whose memory-first lookup would answer with this process's own cache and hide entries written by other processes.



160
161
162
163
164
# File 'lib/magick/audit_log.rb', line 160

def read(feature_name)
  durable_adapters.flat_map do |adapter|
    entries_from(swallow { adapter.get(store_name(feature_name), ENTRIES_KEY) })
  end
end

#read_all ⇒ Object

Every feature's audit history, in one call per adapter.



167
168
169
# File 'lib/magick/audit_log.rb', line 167

def read_all
  durable_adapters.flat_map { |adapter| audit_stores_in(swallow { adapter.load_all_features_data }) }
end

#write(entry, recent = []) ⇒ Object

Append one entry to the shared list for its feature.

recent is this process's tail of the ring: merging it back in means an entry that lost a read-modify-write race against another container is restored by this process's next write, instead of being dropped.



146
147
148
149
150
151
152
153
154
155
# File 'lib/magick/audit_log.rb', line 146

def write(entry, recent = [])
  adapters = durable_adapters
  return false if adapters.empty?

  name = entry.feature_name
  known = recent.select { |e| e.feature_name == name }
  payload = AuditLog.merge(read(name) + known + [entry], limit: retention).map(&:to_h)
  adapters.each { |adapter| swallow { adapter.set(store_name(name), ENTRIES_KEY, payload) } }
  true
end