Class: LockFile Private
Overview
This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.
A lock file to prevent multiple Homebrew processes from modifying the same path.
Direct Known Subclasses
Instance Attribute Summary collapse
- #path ⇒ Object readonly private
Instance Method Summary collapse
- #initialize(type, locked_path) ⇒ void constructor private
- #lock ⇒ void private
- #unlock(unlink: false) ⇒ void private
- #with_lock ⇒ Object private
Constructor Details
#initialize(type, locked_path) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
14 15 16 17 18 19 |
# File 'lock_file.rb', line 14 def initialize(type, locked_path) @locked_path = locked_path lock_name = locked_path.basename.to_s @path = HOMEBREW_LOCKS/"#{lock_name}.#{type}.lock" @lockfile = nil end |
Instance Attribute Details
#path ⇒ Object (readonly)
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
11 12 13 |
# File 'lock_file.rb', line 11 def path @path end |
Instance Method Details
#lock ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
22 23 24 25 26 27 28 29 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 55 56 57 58 59 60 61 62 63 64 |
# File 'lock_file.rb', line 22 def lock ignore_interrupts do next if @lockfile.present? path.dirname.mkpath begin lockfile = begin path.open(File::RDWR | File::CREAT) rescue Errno::EMFILE odie "The maximum number of open files on this system has been reached. " \ "Use `ulimit -n` to increase this limit." end lockfile.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if lockfile.flock(File::LOCK_EX | File::LOCK_NB) # This prevents a race condition in case the file we locked doesn't exist on disk anymore, e.g.: # # 1. Process A creates and opens the file. # 2. Process A locks the file. # 3. Process B opens the file. # 4. Process A unlinks the file. # 5. Process A unlocks the file. # 6. Process B locks the file. # 7. Process C creates and opens the file. # 8. Process C locks the file. # 9. Process B and C hold locks to files with different inode numbers. 💥 if !path.exist? || lockfile.stat.ino != path.stat.ino lockfile.close raise OpenFileChangedOnDisk end @lockfile = lockfile next end rescue OpenFileChangedOnDisk retry end lockfile.close raise OperationInProgressError, @locked_path end end |
#unlock(unlink: false) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
67 68 69 70 71 72 73 74 75 76 |
# File 'lock_file.rb', line 67 def unlock(unlink: false) ignore_interrupts do next if @lockfile.nil? @path.unlink if unlink @lockfile.flock(File::LOCK_UN) @lockfile.close @lockfile = nil end end |
#with_lock ⇒ Object
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
78 79 80 81 82 83 |
# File 'lock_file.rb', line 78 def with_lock lock yield ensure unlock end |