Files
ubicloud/lib/sem_snap.rb
Jeremy Evans 106a52cbef Make Semaphore.incr use a single query
Previously, it would usually use 2 queries if inside a transaction,
or 4 queries if outside a transaction.  This replaces the UPDATE
then INSERT query approach with an INSERT SELECT (UPDATE RETURNING)
approach in a single query.  As this is a single query and not
multiple queries, it does not need a transaction.  If the UPDATE
does not update a row, then no rows will be inserted.

This approach also opens up the ability to create multiple
semaphores in a single query, if the first argument is an array
or a dataset.  That will be used in an upcoming commit.

This changes the return value of Semaphore.incr when provided
a single id from returning a Semaphore instance to returning
the Semaphore uuid.  Only SemSnap#incr cares about the return
value, so update that to fetch the Semaphore.
2025-06-04 05:26:37 +09:00

58 lines
1.1 KiB
Ruby

# frozen_string_literal: true
class SemSnap
def initialize(strand_id, deferred: false)
@deferred = deferred
@strand_id = strand_id
@extant = Hash.new { |h, k| h[k.intern] = [] }
@defer_delete = []
Semaphore.where(strand_id: @strand_id).each do |sem|
add_semaphore_instance_to_snapshot(sem)
end
end
def self.use(strand_id)
new(strand_id, deferred: true).use do |snap|
yield snap
end
end
def use
yield self
ensure
apply
end
def set?(name)
name = name.intern
@extant.include?(name)
end
def decr(name)
name = name.intern
ids = @extant.delete(name)
return unless ids && ids.length > 0
@defer_delete.concat(ids)
apply unless @deferred
end
def incr(name)
if (semaphore = Semaphore.incr(@strand_id, name))
add_semaphore_instance_to_snapshot(Semaphore.with_pk(semaphore))
end
end
private
def apply
return if @defer_delete.empty?
Semaphore.where(strand_id: @strand_id, id: @defer_delete).destroy
@defer_delete.clear
end
def add_semaphore_instance_to_snapshot(sem)
@extant[sem.name.intern] << sem.id
end
end