Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/database/load_balancing/host_list.rb')
-rw-r--r--lib/gitlab/database/load_balancing/host_list.rb99
1 files changed, 99 insertions, 0 deletions
diff --git a/lib/gitlab/database/load_balancing/host_list.rb b/lib/gitlab/database/load_balancing/host_list.rb
new file mode 100644
index 00000000000..24800012947
--- /dev/null
+++ b/lib/gitlab/database/load_balancing/host_list.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module LoadBalancing
+ # A list of database hosts to use for connections.
+ class HostList
+ # hosts - The list of secondary hosts to add.
+ def initialize(hosts = [])
+ @hosts = hosts.shuffle
+ @pools = Set.new
+ @index = 0
+ @mutex = Mutex.new
+ @hosts_gauge = Gitlab::Metrics.gauge(:db_load_balancing_hosts, 'Current number of load balancing hosts')
+
+ set_metrics!
+ update_pools
+ end
+
+ def hosts
+ @mutex.synchronize { @hosts.dup }
+ end
+
+ def shuffle
+ @mutex.synchronize do
+ unsafe_shuffle
+ end
+ end
+
+ def length
+ @mutex.synchronize { @hosts.length }
+ end
+
+ def host_names_and_ports
+ @mutex.synchronize { @hosts.map { |host| [host.host, host.port] } }
+ end
+
+ def manage_pool?(pool)
+ @pools.include?(pool)
+ end
+
+ def hosts=(hosts)
+ @mutex.synchronize do
+ @hosts = hosts
+ unsafe_shuffle
+ update_pools
+ end
+
+ set_metrics!
+ end
+
+ # Sets metrics before returning next host
+ def next
+ next_host.tap do |_|
+ set_metrics!
+ end
+ end
+
+ private
+
+ def unsafe_shuffle
+ @hosts = @hosts.shuffle
+ @index = 0
+ end
+
+ # Returns the next available host.
+ #
+ # Returns a Gitlab::Database::LoadBalancing::Host instance, or nil if no
+ # hosts were available.
+ def next_host
+ @mutex.synchronize do
+ break if @hosts.empty?
+
+ started_at = @index
+
+ loop do
+ host = @hosts[@index]
+ @index = (@index + 1) % @hosts.length
+
+ break host if host.online?
+
+ # Return nil once we have cycled through all hosts and none were
+ # available.
+ break if @index == started_at
+ end
+ end
+ end
+
+ def set_metrics!
+ @hosts_gauge.set({}, @hosts.length)
+ end
+
+ def update_pools
+ @pools = Set.new(@hosts.map(&:pool))
+ end
+ end
+ end
+ end
+end