pesto 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: df40866b281d6ef5590098404180ca334fcbdb57
4
- data.tar.gz: 8f0878c78f7cb2b10199b943ed187bea3840646c
3
+ metadata.gz: e51ff61ac6efa425c0c4a4697c857ccc28e6a0db
4
+ data.tar.gz: 8eb7bba71e8eba452ac5f3bccc94df1f97004b17
5
5
  SHA512:
6
- metadata.gz: cbb914544774964b5be6d8204f78df332a9eb9512f7c70fd3b4af7dac545f85652b9725b3e18c4a9b0cf855079d410b2e6c505f436b4b5791d70bcf8d58b67b7
7
- data.tar.gz: 51791f1f534e3c48c11b0faee8806d9f742aef5e4d0b7b36aff22d6298ae830930d5ae112b9dae4df71dd35c9e59f8e45a17aade2db78128bdcb0ac87ee8398f
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
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
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
@@ -0,0 +1,3 @@
1
+ module Pesto
2
+ VERSION = "0.0.8"
3
+ end
data/lib/pesto.rb CHANGED
@@ -1,132 +1,4 @@
1
- module Pesto
2
- class Lock
3
-
4
- def initialize(ctx = {}, opts = {})
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.6
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-24 00:00:00.000000000 Z
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: paolo@bitfinex.com
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: distributed locking with deadlock prevention
135
+ summary: dlock
43
136
  test_files: []