Module: Tengine::Core::OptimisticLock

Extended by:
ActiveSupport::Concern
Includes:
SafeUpdatable
Included in:
Session
Defined in:
lib/tengine/core/optimistic_lock.rb

Defined Under Namespace

Modules: ClassMethods Classes: RetryOverError

Constant Summary collapse

DEFAULT_RETRY_COUNT =
(ENV['TENGINE_OPTIMISTIC_LOCK_RETRY_MAX'] || 5).to_i

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SafeUpdatable

safemode, #update_in_safe_mode

Class Method Details

.update_with_lock_stackObject



23
24
25
# File 'lib/tengine/core/optimistic_lock.rb', line 23

def update_with_lock_stack
  @update_with_lock_stack ||= []
end

Instance Method Details

#__update_with_lock__Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/tengine/core/optimistic_lock.rb', line 56

def __update_with_lock__
  lock_field_name = self.class.locking_field
  current_version = self.send(lock_field_name)
  hash = as_document.dup.stringify_keys
  hash.delete("_id") # _id not allowed in mod
  new_version = current_version + 1
  hash[lock_field_name.to_s] = new_version
  selector = { :_id => self.id, lock_field_name.to_sym => current_version }
  result = update_in_safe_mode(self.class.collection, selector, hash)
  send("#{lock_field_name}=", new_version)
  result["updatedExisting"] && !result["err"]
end

#update_with_lock(options = {}) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/tengine/core/optimistic_lock.rb', line 30

def update_with_lock(options = {})
  unless Tengine::Core::OptimisticLock.update_with_lock_stack.empty?
    Tengine.logger.warn("Tengine::Core::OptimisticLock#update_with_lock is used in another #update_with_lock.\n  " << caller.join("\n  "))
    Tengine::Core::OptimisticLock.update_with_lock_stack.each do |obj|
      Tengine.logger.warn("-" * 100)
      Tengine.logger.warn("invocation from: #{obj}")
    end
    Tengine.logger.warn("-" * 100)
    Tengine.logger.warn("and invocation from: #{self.inspect}")
  end
  Tengine::Core::OptimisticLock.update_with_lock_stack.push(self.inspect)
  begin
    retry_count = options[:retry] || DEFAULT_RETRY_COUNT
    idx = 1
    while idx <= retry_count
      yield
      return if __update_with_lock__
      reload
      idx += 1
    end
    raise RetryOverError, "retried #{retry_count} times but failed to update"
  ensure
    Tengine::Core::OptimisticLock.update_with_lock_stack.pop
  end
end