lock-smith 0.0.9 → 1.0.0

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.
@@ -14,6 +14,11 @@ module Locksmith
14
14
  !env(key).nil?
15
15
  end
16
16
 
17
+ def pg_lock_space
18
+ n = "LOCKSMITH_PG_LOCK_SPACE"
19
+ env(n) && env(n).to_i
20
+ end
21
+
17
22
  def aws_id
18
23
  @aws_id ||= env!("AWS_ID")
19
24
  end
@@ -9,8 +9,6 @@ module Locksmith
9
9
  @dynamo_lock = Mutex.new
10
10
  @table_lock = Mutex.new
11
11
 
12
- LOCK_TABLE = "Locks"
13
-
14
12
  def lock(name, opts={})
15
13
  opts[:ttl] ||= 60
16
14
  opts[:attempts] ||= 3
@@ -50,17 +48,20 @@ module Locksmith
50
48
  end
51
49
 
52
50
  def locks
53
- table(LOCK_TABLE)
51
+ table(lock_table)
54
52
  end
55
53
 
56
54
  def table(name)
57
- @table_lock.synchronize {tables[name].items}
55
+ unless tables[name]
56
+ @table_lock.synchronize do
57
+ tables[name] = dynamo.tables[name].load_schema
58
+ end
59
+ end
60
+ tables[name].items
58
61
  end
59
62
 
60
63
  def tables
61
- @tables ||= dynamo.tables.
62
- map {|t| t.load_schema}.
63
- reduce({}) {|h, t| h[t.name] = t; h}
64
+ @tables ||= {}
64
65
  end
65
66
 
66
67
  def dynamo
@@ -70,5 +71,13 @@ module Locksmith
70
71
  end
71
72
  end
72
73
 
74
+ def lock_table
75
+ @lock_table
76
+ end
77
+
78
+ def lock_table=(table_name)
79
+ @lock_table = table_name
80
+ end
81
+
73
82
  end
74
83
  end
@@ -1,31 +1,49 @@
1
1
  require 'zlib'
2
2
  require 'uri'
3
+ require 'timeout'
4
+ require 'locksmith/config'
5
+
3
6
  module Locksmith
4
7
  module Pg
5
- extend self
6
- BACKOFF = 0.5
8
+ extend self
7
9
 
8
- def lock(name)
9
- i = Zlib.crc32(name)
10
- result = nil
11
- begin
12
- sleep(BACKOFF) until write_lock(i)
13
- if block_given?
14
- result = yield
10
+ def lock(name, opts={})
11
+ opts[:ttl] ||= 60
12
+ opts[:attempts] ||= 3
13
+ opts[:lspace] ||= (Config.pg_lock_space || -2147483648)
14
+
15
+ if create(name, opts)
16
+ begin Timeout::timeout(opts[:ttl]) {return(yield)}
17
+ ensure delete(name, opts)
15
18
  end
16
- return result
17
- ensure
18
- release_lock(i)
19
19
  end
20
20
  end
21
21
 
22
- def write_lock(i)
23
- r = conn.exec("select pg_try_advisory_lock($1)", [i])
24
- r[0]["pg_try_advisory_lock"] == "t"
22
+ def key(name)
23
+ i = Zlib.crc32(name)
24
+ # We need to wrap the value for postgres
25
+ if i > 2147483647
26
+ -(-(i) & 0xffffffff)
27
+ else
28
+ i
29
+ end
30
+ end
31
+
32
+ def create(name, opts)
33
+ lock_args = [opts[:lspace], key(name)]
34
+ opts[:attempts].times.each do |i|
35
+ res = conn.exec("select pg_try_advisory_lock($1,$2)", lock_args)
36
+ if res[0]["pg_try_advisory_lock"] == "t"
37
+ return(true)
38
+ else
39
+ return(false) if i == (opts[:attempts] - 1)
40
+ end
41
+ end
25
42
  end
26
43
 
27
- def release_lock(i)
28
- conn.exec("select pg_advisory_unlock($1)", [i])
44
+ def delete(name, opts)
45
+ lock_args = [opts[:lspace], key(name)]
46
+ conn.exec("select pg_advisory_unlock($1,$2)", lock_args)
29
47
  end
30
48
 
31
49
  def conn=(conn)
@@ -53,4 +71,3 @@ module Locksmith
53
71
 
54
72
  end
55
73
  end
56
-
data/readme.md CHANGED
@@ -1,13 +1,9 @@
1
- # Locksmith
2
-
3
- **This software is beta quality. Check back later for production quality.**
1
+ # lock-smith
4
2
 
5
3
  A library of locking algorithms for a variety of data stores. Supported Data Stores:
6
4
 
7
5
  * DynamoDB
8
6
  * PostgreSQL
9
- * TODO: Doozerd
10
- * TODO: Zookeeper
11
7
 
12
8
  ## Usage
13
9
 
@@ -58,20 +54,16 @@ Locksmith::Pg.lock("my-resource") do
58
54
  end
59
55
  ```
60
56
 
61
- ## Why Locksmith
57
+ #### Options
62
58
 
63
- Locking code is tricky. Ideally, I would write it once, verify in production for
64
- a year then never think about it again.
59
+ * lspace - This defines which lock space lock-smith will use. This is handy if you have multiple applications using advisory locks.
60
+ * ttl - Wraps your block in a timeout. Be sure to handle `Timeout::Error`.
61
+ * attempts - Number of attempts to try advisory lock. Your code will only run once.
65
62
 
66
63
  ## Hacking on Locksmith
67
64
 
68
65
  There are still some Data Stores to implement, follow the pattern for PostgreSQLand DynamoDB and submit a pull request.
69
66
 
70
- ## Contributors
71
-
72
- * Ryan Smith
73
- * Blake Gentry
74
-
75
67
  ## License
76
68
 
77
69
  Copyright (C) 2012 Ryan Smith
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lock-smith
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -48,4 +48,3 @@ signing_key:
48
48
  specification_version: 3
49
49
  summary: Locking is hard. Write it once.
50
50
  test_files: []
51
- has_rdoc: