admit_one 0.1.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|