Class: RaceGuard::Context::MutableStore

Inherits:
Object
  • Object
show all
Defined in:
lib/race_guard/context.rb

Overview

Mutable per-thread store (never shared across threads).

Constant Summary collapse

RMW_TTL_SEC =

DBLockAuditor::ReadModifyWrite (Epic 4.1) — bounded RMW read journal

2.0
RMW_MAX_ENTRIES =
500

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMutableStore

Returns a new instance of MutableStore.



144
145
146
147
148
149
150
# File 'lib/race_guard/context.rb', line 144

def initialize
  @transaction_depth = 0
  @protected_blocks = []
  @after_commit_stack = []
  @rmw_last_read_at = {}
  @rmw_pessimistic_lock_rows = Set.new
end

Instance Attribute Details

#protected_blocksObject (readonly)

Returns the value of attribute protected_blocks.



182
183
184
# File 'lib/race_guard/context.rb', line 182

def protected_blocks
  @protected_blocks
end

#transaction_depthObject (readonly)

Returns the value of attribute transaction_depth.



182
183
184
# File 'lib/race_guard/context.rb', line 182

def transaction_depth
  @transaction_depth
end

Instance Method Details

#begin_transactionObject



160
161
162
163
# File 'lib/race_guard/context.rb', line 160

def begin_transaction
  @transaction_depth += 1
  @after_commit_stack << []
end

#defer_after_commit(proc) ⇒ Object



174
175
176
177
178
179
180
# File 'lib/race_guard/context.rb', line 174

def defer_after_commit(proc)
  if @after_commit_stack.empty?
    run_after_commit_proc(proc)
  else
    @after_commit_stack.last << proc
  end
end

#end_transaction(success: true) ⇒ Object



165
166
167
168
169
170
171
172
# File 'lib/race_guard/context.rb', line 165

def end_transaction(success: true)
  return unless @transaction_depth.positive?

  callbacks = @after_commit_stack.pop
  @transaction_depth -= 1
  flush_after_commit_callbacks(callbacks, success)
  @rmw_pessimistic_lock_rows.clear if @transaction_depth.zero?
end

#pop_protectedObject



156
157
158
# File 'lib/race_guard/context.rb', line 156

def pop_protected
  @protected_blocks.pop
end

#push_protected(name) ⇒ Object



152
153
154
# File 'lib/race_guard/context.rb', line 152

def push_protected(name)
  @protected_blocks << name.to_sym
end

#rmw_pessimistic_lock_active?(model_class, record_id) ⇒ Boolean

Returns:

  • (Boolean)


222
223
224
# File 'lib/race_guard/context.rb', line 222

def rmw_pessimistic_lock_active?(model_class, record_id)
  @rmw_pessimistic_lock_rows.include?([model_class.object_id, record_id])
end

#rmw_pessimistic_lock_register!(model_class, record_id) ⇒ Object



217
218
219
220
# File 'lib/race_guard/context.rb', line 217

def rmw_pessimistic_lock_register!(model_class, record_id)
  @rmw_pessimistic_lock_rows << [model_class.object_id, record_id]
  self
end

#rmw_read_age_ms_for(model_class, record_id, attr_name) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
# File 'lib/race_guard/context.rb', line 193

def rmw_read_age_ms_for(model_class, record_id, attr_name)
  name = attr_name.to_s
  now = monotonic_time_ms
  key = rmw_key(model_class, record_id, name)
  prune_stale_rmw_map!(now)
  t = @rmw_last_read_at[key]
  return nil unless t
  return nil if (now - t) > (RMW_TTL_SEC * 1000.0)

  (now - t)
end

#rmw_read_forget!(model_class, record_id, attr_name) ⇒ Object



205
206
207
208
209
# File 'lib/race_guard/context.rb', line 205

def rmw_read_forget!(model_class, record_id, attr_name)
  key = rmw_key(model_class, record_id, attr_name.to_s)
  @rmw_last_read_at.delete(key)
  self
end

#rmw_read_forget_record!(model_class, record_id) ⇒ Object



211
212
213
214
215
# File 'lib/race_guard/context.rb', line 211

def rmw_read_forget_record!(model_class, record_id)
  oid = model_class.object_id
  @rmw_last_read_at.delete_if { |k, _| k[0] == oid && k[1] == record_id }
  self
end

#rmw_read_record!(model_class, record_id, attr_name) ⇒ Object



184
185
186
187
188
189
190
191
# File 'lib/race_guard/context.rb', line 184

def rmw_read_record!(model_class, record_id, attr_name)
  name = attr_name.to_s
  now = monotonic_time_ms
  key = rmw_key(model_class, record_id, name)
  prune_stale_rmw_map!(now)
  @rmw_last_read_at[key] = now
  evict_oldest_rmw_reads_if_needed!
end