Class: Gitlab::Database::LoadBalancing::Sticking

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/database/load_balancing/sticking.rb

Overview

Module used for handling sticking connections to a primary, if necessary.

Constant Summary collapse

EXPIRATION =

The number of seconds after which a session should stop reading from the primary.

30
ATOMIC_UNSTICK_SCRIPT =
<<~LUA
  local key = KEYS[1]
  local expected_location = ARGV[1]
  local current_location = redis.call('GET', key)

  if current_location == expected_location then
    redis.call('DEL', key)
    return 1
  else
    return 0
  end
LUA

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(load_balancer) ⇒ Sticking

Returns a new instance of Sticking.



28
29
30
# File 'lib/gitlab/database/load_balancing/sticking.rb', line 28

def initialize(load_balancer)
  @load_balancer = load_balancer
end

Instance Attribute Details

#load_balancerObject (readonly)

Returns the value of attribute load_balancer.



26
27
28
# File 'lib/gitlab/database/load_balancing/sticking.rb', line 26

def load_balancer
  @load_balancer
end

Instance Method Details

#bulk_stick(namespace, ids, hash_id: false) ⇒ Object



79
80
81
82
83
84
85
86
87
88
# File 'lib/gitlab/database/load_balancing/sticking.rb', line 79

def bulk_stick(namespace, ids, hash_id: false)
  with_primary_write_location do |location|
    ids.each do |id|
      id = id_as_hash(id) if hash_id

      set_write_location_for(namespace, id, location)
    end
  end
  use_primary!
end

#find_caught_up_replica(namespace, id, use_primary_on_failure: true, use_primary_on_empty_location: false, hash_id: false) ⇒ Object

Returns true if any caught up replica is found. This does not mean all replicas are caught up but the found caught up replica will be stored in the SafeRequestStore available as LoadBalancer#host for future queries. With use_primary_on_empty_location: true we will assume you need the primary if we can’t find a matching location for the namespace, id pair. You should only use use_primary_on_empty_location in rare cases because we unstick once we find all replicas are caught up one time so it can be wasteful on the primary. If hash_id is true then we only store a hash of id in Redis. This is useful for sensitive data like API tokens.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/gitlab/database/load_balancing/sticking.rb', line 39

def find_caught_up_replica(
  namespace, id,
  use_primary_on_failure: true,
  use_primary_on_empty_location: false,
  hash_id: false)
  id = id_as_hash(id) if hash_id

  location = last_write_location_for(namespace, id)

  result = if location
             up_to_date_result = @load_balancer.select_up_to_date_host(location)

             unstick_if_caught_up(namespace, id, location) if up_to_date_result == LoadBalancer::ALL_CAUGHT_UP

             up_to_date_result != LoadBalancer::NONE_CAUGHT_UP
           else
             # Some callers want to err on the side of caution and be really sure that a caught up replica was
             # found. If we did not have any location to check then we must force `use_primary!` if they they
             # use_primary_on_empty_location
             !use_primary_on_empty_location
           end

  use_primary! if !result && use_primary_on_failure

  result
end

#stick(namespace, id, hash_id: false) ⇒ Object

Starts sticking to the primary for the given namespace and id, using the latest WAL pointer from the primary. If hash_id is true then we only store a hash of id in Redis. This is useful for sensitive data like API tokens.



70
71
72
73
74
75
76
77
# File 'lib/gitlab/database/load_balancing/sticking.rb', line 70

def stick(namespace, id, hash_id: false)
  id = id_as_hash(id) if hash_id

  with_primary_write_location do |location|
    set_write_location_for(namespace, id, location)
  end
  use_primary!
end