admit_one 0.1.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +22 -0
- data/README.md +14 -15
- data/admit_one.gemspec +2 -2
- data/lib/admit_one/lock_file.rb +27 -17
- data/lib/admit_one/version.rb +1 -1
- data/test/unit/lock_file_test.rb +4 -1
- metadata +8 -9
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011 Jonathan S. Garvin (http://www.5valleys.com)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
AdmitOne
|
2
2
|
========
|
3
3
|
|
4
|
-
A Ruby lock file manager that is immune to race conditions.
|
4
|
+
A Ruby lock file manager that is highly resistant, if not outright immune, to race conditions.
|
5
5
|
|
6
6
|
Usage
|
7
7
|
-----
|
@@ -11,7 +11,7 @@ Usage
|
|
11
11
|
# code that needs to run with confidence
|
12
12
|
# that the same code isn't also running
|
13
13
|
# at the same time in another process
|
14
|
-
rescue AdmitOne::
|
14
|
+
rescue AdmitOne::LockFailure
|
15
15
|
# gracefully recover if the lock could not
|
16
16
|
# be established
|
17
17
|
end
|
@@ -55,19 +55,18 @@ append mode. If the file doesn't already exist, it creates it and then opens
|
|
55
55
|
it. Otherwise it just opens it. Then, any writes to the file are appended
|
56
56
|
to the end. Two processes can open and write to the file at the same time.
|
57
57
|
|
58
|
-
AdmitOne
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
The first process will
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
your preferences (such as trying again later, or triggering a missile launch).
|
58
|
+
AdmitOne appends the process id to the end of file, then reads the first
|
59
|
+
line in file to compare it's process id with the one on the first line.
|
60
|
+
In the event of a race condition, two process ids will be written to the
|
61
|
+
file (remember, append mode), but *only one* can possibly be on the first
|
62
|
+
line.
|
63
|
+
|
64
|
+
The first process will confirm that it's process id is on the first line,
|
65
|
+
and only then execute your block of code that needed a lock. The second
|
66
|
+
process will see that the process id on the first line does *not* match
|
67
|
+
it's own, and instead of executing the code block, will raise an exception
|
68
|
+
for your application to catch and handle gracefully according to your
|
69
|
+
preferences (such as trying again later, or triggering a missile launch).
|
71
70
|
|
72
71
|
Contributions
|
73
72
|
-------------
|
data/admit_one.gemspec
CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.authors = ["Jonathan S. Garvin"]
|
8
8
|
s.email = ["jon@5valleys.com"]
|
9
9
|
s.homepage = "https://github.com/jsgarvin/admit_one"
|
10
|
-
s.summary = %q{
|
11
|
-
s.description = %q{
|
10
|
+
s.summary = %q{Race resistant lock file manager.}
|
11
|
+
s.description = %q{Ruby lock file manager that is highly resistant, if not outright immune, to race conditions.}
|
12
12
|
|
13
13
|
s.rubyforge_project = "admit_one"
|
14
14
|
|
data/lib/admit_one/lock_file.rb
CHANGED
@@ -1,42 +1,52 @@
|
|
1
1
|
module AdmitOne
|
2
|
-
|
2
|
+
|
3
3
|
class LockFile
|
4
4
|
require 'tempfile'
|
5
5
|
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :name, :lock_file
|
7
7
|
|
8
8
|
def initialize(name,&block)
|
9
|
-
@
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
@name = name
|
10
|
+
if lock! then
|
11
|
+
begin
|
12
|
+
yield
|
13
|
+
ensure
|
14
|
+
unlock!
|
15
|
+
end
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
19
|
+
#######
|
20
|
+
private
|
21
|
+
#######
|
22
|
+
|
18
23
|
def full_path
|
19
|
-
"#{Dir.tmpdir}/#{
|
24
|
+
"#{Dir.tmpdir}/#{name}.lock"
|
20
25
|
end
|
21
26
|
|
22
27
|
def lock!
|
23
|
-
File.open(full_path, "a")
|
24
|
-
|
28
|
+
@lock_file = File.open(full_path, "a+")
|
29
|
+
lock_file.write("#{Process.pid}\n")
|
30
|
+
lock_file.flush
|
31
|
+
lock_file.rewind
|
32
|
+
raise(LockFailure,'already locked by other process') unless lock_file.gets.to_i == Process.pid
|
33
|
+
return true
|
25
34
|
end
|
26
35
|
|
27
36
|
def unlock!
|
37
|
+
lock_file.close
|
28
38
|
begin
|
29
|
-
File.delete(full_path)
|
39
|
+
File.delete(full_path)
|
30
40
|
rescue
|
31
|
-
|
41
|
+
# This should never happen. It would indicate that another process deleted
|
42
|
+
# a lock file that it didn't rightfully own, or that a user deleted it manually
|
43
|
+
# before this process completed.
|
44
|
+
raise LockFileMissing, 'Lockfile unexpectedly vanished! This should probably be investigated!'
|
32
45
|
end
|
33
46
|
end
|
34
47
|
|
35
|
-
def lock_file_acquired?
|
36
|
-
File.open(full_path, "r") { |file| file.gets.to_i == Process.pid }
|
37
|
-
end
|
38
48
|
end
|
39
49
|
|
40
|
-
class
|
50
|
+
class LockFailure < StandardError; end
|
41
51
|
class LockFileMissing < StandardError; end
|
42
52
|
end
|
data/lib/admit_one/version.rb
CHANGED
data/test/unit/lock_file_test.rb
CHANGED
@@ -8,15 +8,18 @@ class LockFileTest < Test::Unit::TestCase
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_should_create_and_remove_lockfile
|
11
|
+
block_executed = false
|
11
12
|
AdmitOne::LockFile.new(:admit_one_lock_file_unit_test) do
|
13
|
+
block_executed = true
|
12
14
|
assert(File.exist?(lock_file_path))
|
13
15
|
end
|
16
|
+
assert(block_executed)
|
14
17
|
assert(!File.exist?(lock_file_path))
|
15
18
|
end
|
16
19
|
|
17
20
|
def test_should_not_clobber_another_lock_file
|
18
21
|
File.open(lock_file_path, "a") { |file| file.write("1\n") }
|
19
|
-
assert_raise(AdmitOne::
|
22
|
+
assert_raise(AdmitOne::LockFailure) do
|
20
23
|
AdmitOne::LockFile.new(:admit_one_lock_file_unit_test) do
|
21
24
|
assert false #should never run
|
22
25
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 2
|
9
|
+
version: 0.2.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jonathan S. Garvin
|
@@ -14,11 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-05-
|
17
|
+
date: 2011-05-21 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
21
|
-
description:
|
21
|
+
description: Ruby lock file manager that is highly resistant, if not outright immune, to race conditions.
|
22
22
|
email:
|
23
23
|
- jon@5valleys.com
|
24
24
|
executables: []
|
@@ -29,6 +29,7 @@ extra_rdoc_files: []
|
|
29
29
|
|
30
30
|
files:
|
31
31
|
- .gitignore
|
32
|
+
- LICENSE
|
32
33
|
- README.md
|
33
34
|
- Rakefile
|
34
35
|
- admit_one.gemspec
|
@@ -46,7 +47,6 @@ rdoc_options: []
|
|
46
47
|
require_paths:
|
47
48
|
- lib
|
48
49
|
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
@@ -54,7 +54,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
54
|
- 0
|
55
55
|
version: "0"
|
56
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
57
|
requirements:
|
59
58
|
- - ">="
|
60
59
|
- !ruby/object:Gem::Version
|
@@ -64,9 +63,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
63
|
requirements: []
|
65
64
|
|
66
65
|
rubyforge_project: admit_one
|
67
|
-
rubygems_version: 1.3.
|
66
|
+
rubygems_version: 1.3.6
|
68
67
|
signing_key:
|
69
68
|
specification_version: 3
|
70
|
-
summary:
|
69
|
+
summary: Race resistant lock file manager.
|
71
70
|
test_files:
|
72
71
|
- test/unit/lock_file_test.rb
|