summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJacob Vosmaer <contact@jacobvosmaer.nl>2016-03-10 10:41:16 +0100
committerJacob Vosmaer <contact@jacobvosmaer.nl>2016-03-10 10:41:16 +0100
commitcda0b7e1b142130fd2e4d7073e451a3f8d73b693 (patch)
tree0d60230f7a4b3bbaab4d5d21e75a837fe1685801 /lib
parentacd9bc0213098a5626499021eb72595eb556f9be (diff)
downloadgitlab-ce-cda0b7e1b142130fd2e4d7073e451a3f8d73b693.tar.gz
Rename ExpiringLock to ExclusiveLease
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/exclusive_lease.rb37
-rw-r--r--lib/gitlab/expiring_lock.rb52
-rw-r--r--lib/gitlab/ldap/access.rb2
3 files changed, 38 insertions, 53 deletions
diff --git a/lib/gitlab/exclusive_lease.rb b/lib/gitlab/exclusive_lease.rb
new file mode 100644
index 00000000000..f801e8b60b3
--- /dev/null
+++ b/lib/gitlab/exclusive_lease.rb
@@ -0,0 +1,37 @@
+require 'securerandom'
+
+module Gitlab
+ # This class implements an 'exclusive lease'. We call it a 'lease'
+ # because it has a set expiry time. We call it 'exclusive' because only
+ # one caller may obtain a lease for a given key at a time. The
+ # implementation is intended to work across GitLab processes and across
+ # servers. It is a 'cheap' alternative to using SQL queries and updates:
+ # you do not need to change the SQL schema to start using
+ # ExclusiveLease.
+ class ExclusiveLease
+ def initialize(key, timeout)
+ @key, @timeout = key, timeout
+ end
+
+ # Try to obtain the lease. Return true on succes,
+ # false if the lease is already taken.
+ def try_obtain
+ !!redis.set(redis_key, redis_value, nx: true, ex: @timeout)
+ end
+
+ private
+
+ def redis
+ # Maybe someday we want to use a connection pool...
+ @redis ||= Redis.new(url: Gitlab::RedisConfig.url)
+ end
+
+ def redis_key
+ "gitlab:exclusive_lease:#{@key}"
+ end
+
+ def redis_value
+ @redis_value ||= SecureRandom.hex(10)
+ end
+ end
+end
diff --git a/lib/gitlab/expiring_lock.rb b/lib/gitlab/expiring_lock.rb
deleted file mode 100644
index ef77a24cf7d..00000000000
--- a/lib/gitlab/expiring_lock.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-module Gitlab
- # This class implements a distributed self-expiring lock.
- #
- # [2] pry(main)> l = Gitlab::ExpiringLock.new('foobar', 5)
- # => #<Gitlab::ExpiringLock:0x007ffb9d7cb7f8 @key="foobar", @timeout=5>
- # [3] pry(main)> l.try_lock
- # => true
- # [4] pry(main)> l.try_lock # Only the first try_lock succeeds
- # => false
- # [5] pry(main)> l.locked?
- # => true
- # [6] pry(main)> sleep 5
- # => 5
- # [7] pry(main)> l.locked? # After the timeout the lock is released
- # => false
- #
- class ExpiringLock
- def initialize(key, timeout)
- @key, @timeout = key, timeout
- end
-
- # Try to obtain the lock. Return true on succes,
- # false if the lock is already taken.
- def try_lock
- # INCR does not change the key TTL
- if redis.incr(redis_key) == 1
- # We won the race to insert the key into Redis
- redis.expire(redis_key, @timeout)
- true
- else
- # Somebody else won the race
- false
- end
- end
-
- # Check if somebody somewhere locked this key
- def locked?
- !!redis.get(redis_key)
- end
-
- private
-
- def redis
- # Maybe someday we want to use a connection pool...
- @redis ||= Redis.new(url: Gitlab::RedisConfig.url)
- end
-
- def redis_key
- "gitlab:expiring_lock:#{@key}"
- end
- end
-end
diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb
index 29347c05b7d..76786169a49 100644
--- a/lib/gitlab/ldap/access.rb
+++ b/lib/gitlab/ldap/access.rb
@@ -10,7 +10,7 @@ module Gitlab
LOCK_TIMEOUT = 600
def self.try_lock_user(user)
- Gitlab::ExpiringLock.new("user_ldap_check:#{user.id}", LOCK_TIMEOUT).try_lock
+ Gitlab::ExclusiveLease.new("user_ldap_check:#{user.id}", LOCK_TIMEOUT).try_obtain
end
def self.open(user, &block)