Class: Internaut::SystemLock

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

Constant Summary collapse

@@enabled =
true

Class Method Summary collapse

Class Method Details

.critical_section(unique_code_block_identifier, timeout = 60) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/system_lock.rb', line 44

def self.critical_section(unique_code_block_identifier, timeout=60)
  # puts "entering cc #{Process.pid}"
  yield and return unless @@enabled

  begin
    path = "SystemLock::#{unique_code_block_identifier}"
    # puts "waiting for lock..."
    # wait until the lock is released or until we timeout

    # We use a combination of the process id and a unique app id in case the process id is the same on two different machines
    unique_process_id = UNIQUE_APPLICATION_INSTANCE_ID + Process.pid.to_s
    got_the_lock = false
    while( !got_the_lock )
      while( (cache = @@CACHE.get(path)) && (cache[0] != unique_process_id) rescue return ) do
        # puts "locked waiting.... #{path}: #{Process.pid} : #{cache.inspect}"
        sleep(0.1)
      end
      
      counter = cache && cache[1]
      counter ||= 0
      # set the lock
      set_lock_to = [unique_process_id,counter]
      # puts "attempting to grab lock: #{set_lock_to.inspect}"
      @@CACHE.set( path, set_lock_to, timeout.seconds.to_i )
      cache = @@CACHE.get(path)
      if cache && (cache[0] == unique_process_id)
        # we have to double check to make sure we actually got the lock
        # sleep(0.1)
        cache = @@CACHE.get(path)
        if cache && (cache[0] == unique_process_id)
          # puts "got the lock"
          got_the_lock = true
          
          # puts "grabbing lock: #{set_lock_to.inspect}"
          # add reference - we use ref counting for recursive calls
          set_lock_to = [unique_process_id,cache[1]+1]
          @@CACHE.set( path, set_lock_to, timeout.seconds.to_i ) 
        else
          redo
        end
      else
        # puts "redoing: #{RefCounter.get(path)}, #{unique_process_id}"
        redo
      end
    end
    # puts "acquired lock #{Process.pid}"
    CacheTest.add "entering #{Process.pid}" if Rails.env.test?

    # Do the action
    yield

    CacheTest.add "exiting #{Process.pid}" if Rails.env.test?
    # puts "leaving lock #{Process.pid}"
  # make sure we always unlock, even if there is an exception
  ensure
    cache = @@CACHE.get(path)
    if cache
      if cache[1] > 1
        
        cache[1] -= 1
        # puts "decrementing count to #{cache.inspect}"
        @@CACHE.set( path, cache)
      else
        @@CACHE.set( path, nil)
        # puts "decrementing count to nil - #{path}"
      end
    end
  end
end

.disable!Object



24
25
26
# File 'lib/system_lock.rb', line 24

def self.disable!
  @@enabled = false
end

.enable!Object



28
29
30
# File 'lib/system_lock.rb', line 28

def self.enable!
  @@enabled = true
end

.enabled?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/system_lock.rb', line 32

def self.enabled?
  @@enabled
end

.memcached_instanceObject



40
41
42
# File 'lib/system_lock.rb', line 40

def self.memcached_instance
  @@CACHE
end

.memcached_instance=(cache) ⇒ Object



36
37
38
# File 'lib/system_lock.rb', line 36

def self.memcached_instance= cache
  @@CACHE = cache
end