Class: SafeFlock::Lockfile

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

Overview

Thread-safe, transferable, flock-based lock file implementation

See create for a safe way to wrap the creation, locking and unlocking of the lock file.

Constant Summary collapse

@@global_mutex =
Mutex.new
@@path_mutex =
{}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, max_wait: 5.0) ⇒ Lockfile

Initialize (but do not lock)

See SafeFlock.create for a safe way to wrap the creation, locking and unlocking of the lock file.



20
21
22
23
24
25
26
27
28
# File 'lib/safe_flock/lockfile.rb', line 20

def initialize(path, max_wait: 5.0)
  @pid = $$
  @thread_id = Thread.current.object_id
  @path = path
  @max_wait = max_wait
  @wait_per_try = 0.1
  @mlocked = false
  @lockfd = nil
end

Instance Attribute Details

#pathObject (readonly)

The path to the lock file



85
86
87
# File 'lib/safe_flock/lockfile.rb', line 85

def path
  @path
end

#pidObject (readonly)

The process that created the lock file



90
91
92
# File 'lib/safe_flock/lockfile.rb', line 90

def pid
  @pid
end

#thread_idObject (readonly)

A unique identifier for the thread that created the lock file



95
96
97
# File 'lib/safe_flock/lockfile.rb', line 95

def thread_id
  @thread_id
end

Instance Method Details

#locktrue|false

Lock the lock file

See SafeFlock.create for a safe way to wrap the creation, locking and unlocking of the lock file.

Attempt to File#flock the lock file, creating it if necessary.

If max_wait is zero, the attempt is non-blocking: if the file is already locked, give up immediately. Otherwise, continue trying to lock the file for approximately max_wait seconds.

The operation is performed under a per-path thread mutex to preserve mutual exclusion across threads.

Returns:

  • (true|false)

    whether the lock was acquired

Raises:

  • (Exception)

    if an IO error occurs opening the lock file e.g. Errno::EACCES



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/safe_flock/lockfile.rb', line 49

def lock
  deadline = Time.now.to_f + @max_wait
  while !(is_locked = try_lock)
    if Time.now.to_f < deadline
      sleep @wait_per_try
    else
      break
    end
  end
  is_locked
end

#unlockObject

Unlock the lock file

See SafeFlock.create for a safe way to wrap the creation, locking and unlocking of the lock file.

Unlock the lock file in the current process.

The only intended use case for this method is in a forked child process that does significant work after the mutually exclusive work for which it required the lock. In such cases, the process may call unlock after the mutually exclusive work is complete.



72
73
74
75
76
77
78
79
80
# File 'lib/safe_flock/lockfile.rb', line 72

def unlock
  if @lockfd
    @lockfd.close
    @lockfd = nil
  end
  if @mlocked && @pid == $$ and @thread_id == Thread.current.object_id
    mutex_unlock
  end
end