Class: Procrastinator::FileTransaction
- Inherits:
-
Object
- Object
- Procrastinator::FileTransaction
- Defined in:
- lib/procrastinator/task_store/file_transaction.rb
Overview
The general idea is that there may be two threads that need to do these actions on the same file:
thread A: read
thread B: read
thread A/B: write
thread A/B: write
When this sequence happens, the second file write is based on old information and loses the info from the prior write. Using a global mutex per file path prevents this case.
This situation can also occur with multi processing, so file locking is also used for solitary access. File locking is only advisory in some systems, though, so it may only work against other applications that request a lock.
Direct Known Subclasses
Class Attribute Summary collapse
-
.file_mutex ⇒ Object
readonly
Returns the value of attribute file_mutex.
Instance Method Summary collapse
-
#initialize(path) ⇒ FileTransaction
constructor
A new instance of FileTransaction.
-
#read(&block) ⇒ Object
Alias for transact(writable: false).
-
#transact(writable: false) ⇒ Object
Completes the given block as an atomic transaction locked using a global mutex table.
-
#write(&block) ⇒ Object
Alias for transact(writable: true).
Constructor Details
#initialize(path) ⇒ FileTransaction
Returns a new instance of FileTransaction.
28 29 30 |
# File 'lib/procrastinator/task_store/file_transaction.rb', line 28 def initialize(path) @path = ensure_path(path) end |
Class Attribute Details
.file_mutex ⇒ Object (readonly)
Returns the value of attribute file_mutex.
25 26 27 |
# File 'lib/procrastinator/task_store/file_transaction.rb', line 25 def file_mutex @file_mutex end |
Instance Method Details
#read(&block) ⇒ Object
Alias for transact(writable: false)
33 34 35 |
# File 'lib/procrastinator/task_store/file_transaction.rb', line 33 def read(&block) transact(writable: false, &block) end |
#transact(writable: false) ⇒ Object
Completes the given block as an atomic transaction locked using a global mutex table. The block is provided the current file contents. The block’s result is written to the file.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/procrastinator/task_store/file_transaction.rb', line 45 def transact(writable: false) semaphore = FileTransaction.file_mutex[@path.to_s] ||= Mutex.new semaphore.synchronize do @path.open(writable ? 'r+' : 'r') do |file| file.flock(File::LOCK_EX) yield_result = yield(file.read) if writable file.rewind file.write yield_result file.truncate(file.pos) end yield_result end end end |
#write(&block) ⇒ Object
Alias for transact(writable: true)
38 39 40 |
# File 'lib/procrastinator/task_store/file_transaction.rb', line 38 def write(&block) transact(writable: true, &block) end |