require 'socket' require 'thread' module Mongoid module Lock def local_mutex @__mutex ||= Mutex.new end def reset_lock! self.update_attributes(:lock_used_by => nil, :lock_acquired_at => nil, :lock_waiter => nil) end def lock_acquire self.lock_acquire_begin local = "#{Socket.gethostname}:#{Process.pid}" ident = self.lock_used_by wait = self.lock_waiter if (ident and ident != local) raise Mongoid::Lock::UnsynchronizedAccess.new(ident) elsif (wait != local) raise Mongoid::Lock::UnsynchronizedAccess.new(wait) else self.set(:lock_used_by, local) self.set(:lock_acquired_at, Time.now) self.set(:lock_waiter, nil) end end def lock_acquire_begin local = "#{Socket.gethostname}:#{Process.pid}" ident = self.lock_used_by wait = self.lock_waiter if (ident or wait) raise Mongoid::Lock::UnsynchronizedAccess.new(ident) else self.set(:lock_waiter, local) end end def lock_release local = "#{Socket.gethostname}:#{Process.pid}" ident = self.lock_used_by if (ident and ident == local) self.reset_lock! else raise Mongoid::Lock::UnsynchronizedAccess.new(ident) end end def synchronized(&block) self.local_mutex.synchronize { self.lock_acquire begin block.call() ensure self.lock_release end } end def try_synchronized(&try_block) begin self.synchronized do try_block.call() end return true rescue Mongoid::Lock::UnsynchronizedAccess => ua return false end end def wait_synchronized(timeout, &block) started = Time.now expires = started + timeout begin success = self.try_synchronized do block.call() end unless (success) sleep(2) end end while(not success and Time.now < expires) return success end end end