pesto 0.0.6 → 0.0.8
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.
- checksums.yaml +4 -4
- data/.gitignore +50 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +49 -0
- data/README.md +1 -0
- data/examples/aggressive.rb +62 -0
- data/lib/pesto/lock.rb +122 -0
- data/lib/pesto/version.rb +3 -0
- data/lib/pesto.rb +4 -132
- data/pesto.gemspec +23 -0
- metadata +98 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e51ff61ac6efa425c0c4a4697c857ccc28e6a0db
|
4
|
+
data.tar.gz: 8eb7bba71e8eba452ac5f3bccc94df1f97004b17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff893fccea20d6ec74171778da24e97ac0ec65e4bb42be2f6e581756ed9dfc17bd2324c136ff32c22e3f109061d25c3b919834886c999e08f3ae43631f912b7c
|
7
|
+
data.tar.gz: c5d05678bbd4b8ee1107d35f913c0dfd34e2206d6454bfc485e07d021b78f87dff6dd459eac34faa3130f5e291ee1e81d5a829b8e446f8081db634bcfe808f70
|
data/.gitignore
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pesto (0.0.7)
|
5
|
+
connection_pool (~> 2.2)
|
6
|
+
hiredis (~> 0.6)
|
7
|
+
redis (~> 3.3)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
connection_pool (2.2.1)
|
13
|
+
diff-lcs (1.3)
|
14
|
+
docile (1.1.5)
|
15
|
+
fakeredis (0.6.0)
|
16
|
+
redis (~> 3.2)
|
17
|
+
hiredis (0.6.1)
|
18
|
+
json (2.1.0)
|
19
|
+
redis (3.3.3)
|
20
|
+
rspec (3.6.0)
|
21
|
+
rspec-core (~> 3.6.0)
|
22
|
+
rspec-expectations (~> 3.6.0)
|
23
|
+
rspec-mocks (~> 3.6.0)
|
24
|
+
rspec-core (3.6.0)
|
25
|
+
rspec-support (~> 3.6.0)
|
26
|
+
rspec-expectations (3.6.0)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.6.0)
|
29
|
+
rspec-mocks (3.6.0)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.6.0)
|
32
|
+
rspec-support (3.6.0)
|
33
|
+
simplecov (0.14.1)
|
34
|
+
docile (~> 1.1.0)
|
35
|
+
json (>= 1.8, < 3)
|
36
|
+
simplecov-html (~> 0.10.0)
|
37
|
+
simplecov-html (0.10.1)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
fakeredis (~> 0.6)
|
44
|
+
pesto!
|
45
|
+
rspec (~> 3.6)
|
46
|
+
simplecov (~> 0.14)
|
47
|
+
|
48
|
+
BUNDLED WITH
|
49
|
+
1.13.6
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# pesto
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'connection_pool'
|
2
|
+
require 'hiredis'
|
3
|
+
require 'redis'
|
4
|
+
require 'securerandom'
|
5
|
+
require_relative '../lib/pesto.rb'
|
6
|
+
|
7
|
+
$use_sleep = false
|
8
|
+
$key_num = 20
|
9
|
+
$concurrency = 10
|
10
|
+
|
11
|
+
def lock(ctx, pfx, pid = 0)
|
12
|
+
pl = Pesto::Lock.new({ :pool => ctx[:pool], :verbose => true })
|
13
|
+
keys = []
|
14
|
+
|
15
|
+
for i in 0..$key_num
|
16
|
+
keys << "pesto:#{pfx}:#{i}"
|
17
|
+
end
|
18
|
+
|
19
|
+
keys.shuffle!
|
20
|
+
|
21
|
+
d1 = Time.now
|
22
|
+
|
23
|
+
locked = pl.lock(keys, timeout_lock: 0.05, interval_check: 0.005 )
|
24
|
+
|
25
|
+
if locked == 1
|
26
|
+
pl.unlock(keys)
|
27
|
+
puts "[#{pid}] lock acquired/dismissed (took: #{(Time.now - d1) * 1000}ms)"
|
28
|
+
else
|
29
|
+
puts "[#{pid}] lock failed"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
pfx = SecureRandom.hex(10)
|
34
|
+
children = []
|
35
|
+
|
36
|
+
def killall(pids)
|
37
|
+
pids.each do |pid|
|
38
|
+
Process.kill 9, pid
|
39
|
+
end
|
40
|
+
Process.exit
|
41
|
+
end
|
42
|
+
|
43
|
+
Signal.trap('INT') { killall(children) }
|
44
|
+
Signal.trap('TERM') { killall(children) }
|
45
|
+
|
46
|
+
for pid in 0..$concurrency
|
47
|
+
puts "[#{pid}] fork"
|
48
|
+
children << fork do
|
49
|
+
redis = ConnectionPool.new(size: 5, :timeout => 10) { Redis.new(:driver => :hiredis) }
|
50
|
+
while true do
|
51
|
+
lock({ :pool => redis }, pfx, pid)
|
52
|
+
if use_sweep
|
53
|
+
delay = rand(1000).to_f / 10000.0
|
54
|
+
sleep delay
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
while true do
|
61
|
+
sleep 1
|
62
|
+
end
|
data/lib/pesto/lock.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module Pesto
|
2
|
+
class Lock
|
3
|
+
|
4
|
+
def initialize(ctx = {}, opts = {})
|
5
|
+
@ctx = ctx
|
6
|
+
|
7
|
+
raise 'ERR_REDIS_NOTFOUND' if @ctx[:pool].nil?
|
8
|
+
|
9
|
+
@conf = {
|
10
|
+
:lock_expire => true,
|
11
|
+
:timeout_lock_expire => 5,
|
12
|
+
:timeout_lock => 1,
|
13
|
+
:interval_check => 0.05
|
14
|
+
}.merge(opts)
|
15
|
+
end
|
16
|
+
|
17
|
+
def conf
|
18
|
+
@conf
|
19
|
+
end
|
20
|
+
|
21
|
+
def cp
|
22
|
+
@ctx[:pool]
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge_options o = {}, *filter
|
26
|
+
c = conf.merge(o)
|
27
|
+
c.delete_if{|k,v| !filter.include?(k) } unless filter.empty?
|
28
|
+
c
|
29
|
+
end
|
30
|
+
|
31
|
+
def lock _names, _opts = {}
|
32
|
+
opts = merge_options _opts, :timeout_lock_expire, :timeout_lock, :interval_check
|
33
|
+
|
34
|
+
names = (_names.is_a?(String) ? [_names] : _names).uniq
|
35
|
+
opts[:timeout_lock_expire] = opts[:timeout_lock_expire].to_i
|
36
|
+
opts[:timeout_lock_expire] += opts[:timeout_lock] * names.size
|
37
|
+
|
38
|
+
t_start = Time.now
|
39
|
+
|
40
|
+
while true
|
41
|
+
res, locks, stop = get_locks names
|
42
|
+
|
43
|
+
expire names, opts if !stop && conf[:lock_expire]
|
44
|
+
|
45
|
+
break if stop || (Time.now - t_start) > opts[:timeout_lock]
|
46
|
+
|
47
|
+
unlock locks
|
48
|
+
sleep opts[:interval_check]
|
49
|
+
end
|
50
|
+
|
51
|
+
stop ? 1 : 0
|
52
|
+
end
|
53
|
+
|
54
|
+
def expire names, opts={}
|
55
|
+
cp.with do |rc|
|
56
|
+
rc.pipelined do
|
57
|
+
names.each do |n|
|
58
|
+
rc.expire lock_hash(n), opts[:timeout_lock_expire].to_i
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_locks names
|
65
|
+
locked = 0
|
66
|
+
locks = []
|
67
|
+
res = []
|
68
|
+
|
69
|
+
cp.with do |rc|
|
70
|
+
res = rc.pipelined do
|
71
|
+
names.each do |n|
|
72
|
+
rc.setnx lock_hash(n), 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
names.each_with_index do |n, ix|
|
77
|
+
next unless res[ix]
|
78
|
+
locked += 1
|
79
|
+
locks.push n
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
return [res, locks, locked == names.size]
|
84
|
+
end
|
85
|
+
|
86
|
+
def locki name = 'global', opts = {}
|
87
|
+
lock name, opts.merge(timeout_lock: 0)
|
88
|
+
end
|
89
|
+
|
90
|
+
def lockx name = 'global', opts = {}, err = 'ERR_LOCKING'
|
91
|
+
locked = lock(name, opts)
|
92
|
+
return 1 if locked == 1
|
93
|
+
|
94
|
+
raise "#{err} (#{name})"
|
95
|
+
end
|
96
|
+
|
97
|
+
def unlock _names = []
|
98
|
+
_names = [_names] if _names.is_a?(String)
|
99
|
+
names = _names.uniq
|
100
|
+
res = []
|
101
|
+
|
102
|
+
cp.with do |rc|
|
103
|
+
res = rc.pipelined do
|
104
|
+
names.each do |n|
|
105
|
+
rc.del(lock_hash(n))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
val = res.reduce(0){|sum,n| sum+n}
|
111
|
+
|
112
|
+
val > 0 ? 1 : 0
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def lock_hash name
|
118
|
+
"pesto:lock:#{name}"
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
data/lib/pesto.rb
CHANGED
@@ -1,132 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
@ctx = ctx
|
6
|
-
|
7
|
-
raise 'ERR_REDIS_NOTFOUND' if @ctx[:redis].nil?
|
8
|
-
|
9
|
-
@conf = {
|
10
|
-
:lock_expire => true,
|
11
|
-
:timeout_lock_expire => 5,
|
12
|
-
:timeout_lock => 1,
|
13
|
-
:interval_check => 0.05
|
14
|
-
}.merge(opts)
|
15
|
-
end
|
16
|
-
|
17
|
-
def rc
|
18
|
-
@ctx[:redis]
|
19
|
-
end
|
20
|
-
|
21
|
-
def lock(_names, _opts = {})
|
22
|
-
opts = {}.merge(
|
23
|
-
@conf.select{ |k| [
|
24
|
-
:timeout_lock_expire, :timeout_lock,
|
25
|
-
:interval_check
|
26
|
-
].include?(k)
|
27
|
-
}
|
28
|
-
).merge(_opts || {})
|
29
|
-
|
30
|
-
_names = [_names] if _names.is_a?(String)
|
31
|
-
names = _names.uniq
|
32
|
-
|
33
|
-
opts[:timeout_lock_expire] = (opts[:timeout_lock_expire] + (opts[:timeout_lock] * names.size)).to_i
|
34
|
-
|
35
|
-
t_start = Time.now
|
36
|
-
locked = 0
|
37
|
-
|
38
|
-
while true
|
39
|
-
locked = 0
|
40
|
-
|
41
|
-
lock_req = nil
|
42
|
-
rc.with do |rc|
|
43
|
-
lock_req = rc.pipelined do
|
44
|
-
names.each do |n|
|
45
|
-
chash = lock_hash(n)
|
46
|
-
rc.setnx chash, 1
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
locks = []
|
52
|
-
|
53
|
-
if lock_req
|
54
|
-
names.each_with_index do |n, ix|
|
55
|
-
l = lock_req[ix]
|
56
|
-
next if !l
|
57
|
-
locked += 1
|
58
|
-
locks << n
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
if locked == names.size
|
63
|
-
locked = 1
|
64
|
-
|
65
|
-
if @conf[:lock_expire]
|
66
|
-
rc.with do |rc|
|
67
|
-
rc.pipelined do
|
68
|
-
names.each do |n|
|
69
|
-
chash = lock_hash(n)
|
70
|
-
rc.expire chash, opts[:timeout_lock_expire]
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
else
|
76
|
-
locked = 0
|
77
|
-
end
|
78
|
-
|
79
|
-
break if locked == 1 || (Time.now - t_start) > opts[:timeout_lock]
|
80
|
-
|
81
|
-
unlock(locks)
|
82
|
-
sleep opts[:interval_check]
|
83
|
-
end
|
84
|
-
|
85
|
-
locked == 0 ? 0 : 1
|
86
|
-
end
|
87
|
-
|
88
|
-
def locki(name = 'global', _opts = {})
|
89
|
-
opts = (_opts || {}).merge({ :timeout_lock => 0 })
|
90
|
-
lock(name, opts)
|
91
|
-
end
|
92
|
-
|
93
|
-
def lockx(name = 'global', opts = {}, err = 'ERR_LOCKING')
|
94
|
-
locked = lock(name, opts)
|
95
|
-
if locked == 1
|
96
|
-
return 1
|
97
|
-
end
|
98
|
-
raise "#{err} (#{name})"
|
99
|
-
end
|
100
|
-
|
101
|
-
def unlock(_names)
|
102
|
-
_names = [_names] if _names.is_a?(String)
|
103
|
-
names = _names.uniq
|
104
|
-
|
105
|
-
unlock_req = nil
|
106
|
-
rc.with do |rc|
|
107
|
-
unlock_req = rc.pipelined do
|
108
|
-
names.each do |n|
|
109
|
-
rc.del(lock_hash(n))
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
val = 0
|
115
|
-
|
116
|
-
if unlock_req
|
117
|
-
unlock_req.each do |v|
|
118
|
-
val += v
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
val > 0 ? 1 : 0
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
def lock_hash(name)
|
128
|
-
"pesto:lock:#{name}"
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
1
|
+
require 'hiredis'
|
2
|
+
require 'redis'
|
3
|
+
require 'connection_pool'
|
4
|
+
require 'pesto/lock'
|
data/pesto.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'pesto/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'pesto'
|
7
|
+
s.version = Pesto::VERSION
|
8
|
+
s.summary = 'dlock'
|
9
|
+
s.description = 'distributed locking with deadlock prevention'
|
10
|
+
s.authors = ['bfx devs']
|
11
|
+
s.email = 'info@bitfinex.com'
|
12
|
+
s.homepage = 'https://www.bitfinex.com'
|
13
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
|
16
|
+
s.add_runtime_dependency "hiredis", "~> 0.6"
|
17
|
+
s.add_runtime_dependency "redis", "~> 3.3"
|
18
|
+
s.add_runtime_dependency "connection_pool", "~> 2.2"
|
19
|
+
|
20
|
+
s.add_development_dependency "rspec", "~> 3.6"
|
21
|
+
s.add_development_dependency "fakeredis", "~> 0.6"
|
22
|
+
s.add_development_dependency "simplecov", "~> 0.14"
|
23
|
+
end
|
metadata
CHANGED
@@ -1,22 +1,115 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pesto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bfx devs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
12
|
-
dependencies:
|
11
|
+
date: 2017-05-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hiredis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: connection_pool
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: fakeredis
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.6'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.14'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.14'
|
13
97
|
description: distributed locking with deadlock prevention
|
14
|
-
email:
|
98
|
+
email: info@bitfinex.com
|
15
99
|
executables: []
|
16
100
|
extensions: []
|
17
101
|
extra_rdoc_files: []
|
18
102
|
files:
|
103
|
+
- ".gitignore"
|
104
|
+
- ".rspec"
|
105
|
+
- Gemfile
|
106
|
+
- Gemfile.lock
|
107
|
+
- README.md
|
108
|
+
- examples/aggressive.rb
|
19
109
|
- lib/pesto.rb
|
110
|
+
- lib/pesto/lock.rb
|
111
|
+
- lib/pesto/version.rb
|
112
|
+
- pesto.gemspec
|
20
113
|
homepage: https://www.bitfinex.com
|
21
114
|
licenses: []
|
22
115
|
metadata: {}
|
@@ -39,5 +132,5 @@ rubyforge_project:
|
|
39
132
|
rubygems_version: 2.4.8
|
40
133
|
signing_key:
|
41
134
|
specification_version: 4
|
42
|
-
summary:
|
135
|
+
summary: dlock
|
43
136
|
test_files: []
|