class Octopus::ProxyConfig

Constants

BLOCK_KEY
CURRENT_GROUP_KEY
CURRENT_LOAD_BALANCE_OPTIONS_KEY
CURRENT_MODEL_KEY
CURRENT_SHARD_KEY
CURRENT_SLAVE_GROUP_KEY
FULLY_REPLICATED_KEY

Attributes

adapters[RW]
config[RW]
entire_sharded[RW]
groups[RW]
replicated[RW]
sharded[RW]
shards[RW]
shards_config[RW]
shards_slave_groups[RW]
slave_groups[RW]
slaves_list[RW]
slaves_load_balancer[RW]

Public Class Methods

new(config) click to toggle source
# File lib/octopus/proxy_config.rb, line 15
def initialize(config)
  initialize_shards(config)
  initialize_replication(config) if !config.nil? && config['replicated']
end

Public Instance Methods

block() click to toggle source
# File lib/octopus/proxy_config.rb, line 95
def block
  Thread.current[BLOCK_KEY]
end
block=(block) click to toggle source
# File lib/octopus/proxy_config.rb, line 99
def block=(block)
  Thread.current[BLOCK_KEY] = block
end
current_group() click to toggle source
# File lib/octopus/proxy_config.rb, line 65
def current_group
  Thread.current[CURRENT_GROUP_KEY]
end
current_group=(group_symbol) click to toggle source
# File lib/octopus/proxy_config.rb, line 69
def current_group=(group_symbol)
  # TODO: Error message should include all groups if given more than one bad name.
  [group_symbol].flatten.compact.each do |group|
    fail "Nonexistent Group Name: #{group}" unless has_group?(group)
  end

  Thread.current[CURRENT_GROUP_KEY] = group_symbol
end
current_load_balance_options() click to toggle source
# File lib/octopus/proxy_config.rb, line 87
def current_load_balance_options
  Thread.current[CURRENT_LOAD_BALANCE_OPTIONS_KEY]
end
current_load_balance_options=(options) click to toggle source
# File lib/octopus/proxy_config.rb, line 91
def current_load_balance_options=(options)
  Thread.current[CURRENT_LOAD_BALANCE_OPTIONS_KEY] = options
end
current_model() click to toggle source
# File lib/octopus/proxy_config.rb, line 20
def current_model
  Thread.current[CURRENT_MODEL_KEY]
end
current_model=(model) click to toggle source
# File lib/octopus/proxy_config.rb, line 24
def current_model=(model)
  Thread.current[CURRENT_MODEL_KEY] = model.is_a?(ActiveRecord::Base) ? model.class : model
end
current_shard() click to toggle source
# File lib/octopus/proxy_config.rb, line 28
def current_shard
  Thread.current[CURRENT_SHARD_KEY] ||= Octopus.master_shard
end
current_shard=(shard_symbol) click to toggle source
# File lib/octopus/proxy_config.rb, line 32
def current_shard=(shard_symbol)
  if shard_symbol.is_a?(Array)
    self.current_slave_group = nil
    shard_symbol.each { |symbol| fail "Nonexistent Shard Name: #{symbol}" if shards[symbol].nil? }
  elsif shard_symbol.is_a?(Hash)
    hash = shard_symbol
    shard_symbol = hash[:shard]
    slave_group_symbol = hash[:slave_group]
    load_balance_options = hash[:load_balance_options]

    if shard_symbol.nil? && slave_group_symbol.nil?
      fail 'Neither shard or slave group must be specified'
    end

    if shard_symbol.present?
      fail "Nonexistent Shard Name: #{shard_symbol}" if shards[shard_symbol].nil?
    end

    if slave_group_symbol.present?
      if (shards_slave_groups.try(:[], shard_symbol).present? && shards_slave_groups[shard_symbol][slave_group_symbol].nil?) ||
          (shards_slave_groups.try(:[], shard_symbol).nil? && @slave_groups[slave_group_symbol].nil?)
        fail "Nonexistent Slave Group Name: #{slave_group_symbol} in shards config: #{shards_config.inspect}"
      end
    end
    self.current_slave_group = slave_group_symbol
    self.current_load_balance_options = load_balance_options
  else
    fail "Nonexistent Shard Name: #{shard_symbol}" if shards[shard_symbol].nil?
  end

  Thread.current[CURRENT_SHARD_KEY] = shard_symbol
end
current_slave_group() click to toggle source
# File lib/octopus/proxy_config.rb, line 78
def current_slave_group
  Thread.current[CURRENT_SLAVE_GROUP_KEY]
end
current_slave_group=(slave_group_symbol) click to toggle source
# File lib/octopus/proxy_config.rb, line 82
def current_slave_group=(slave_group_symbol)
  Thread.current[CURRENT_SLAVE_GROUP_KEY] = slave_group_symbol
  Thread.current[CURRENT_LOAD_BALANCE_OPTIONS_KEY] = nil if slave_group_symbol.nil?
end
fully_replicated?() click to toggle source
# File lib/octopus/proxy_config.rb, line 103
def fully_replicated?
  @fully_replicated || Thread.current[FULLY_REPLICATED_KEY]
end
has_group?(group) click to toggle source

Public: Whether or not a group exists with the given name converted to a string.

Returns a boolean.

# File lib/octopus/proxy_config.rb, line 111
def has_group?(group)
  @groups.key?(group.to_s)
end
initialize_replication(config) click to toggle source
# File lib/octopus/proxy_config.rb, line 200
def initialize_replication(config)
  @replicated = true
  if config.key?('fully_replicated')
    @fully_replicated = config['fully_replicated']
  else
    @fully_replicated = true
  end

  @slaves_list = shards.keys.map(&:to_s).sort
  @slaves_list.delete('master')
  @slaves_load_balancer = Octopus.load_balancer.new(@slaves_list)
end
initialize_shards(config) click to toggle source
# File lib/octopus/proxy_config.rb, line 134
def initialize_shards(config)
  self.config = config

  self.shards = HashWithIndifferentAccess.new
  self.shards_slave_groups = HashWithIndifferentAccess.new
  self.slave_groups = HashWithIndifferentAccess.new
  self.groups = {}
  self.config = ActiveRecord::Base.connection_pool_without_octopus.spec.config

  unless config.nil?
    self.entire_sharded = config['entire_sharded']
    self.shards_config = config[Octopus.rails_env]
  end

  self.shards_config ||= []

  shards_config.each do |key, value|
    if value.is_a?(String)
      value = resolve_string_connection(value).merge(:octopus_shard => key)
      initialize_adapter(value['adapter'])
      shards[key.to_sym] = connection_pool_for(value, "#{value['adapter']}_connection")
    elsif value.is_a?(Hash) && value.key?('adapter')
      value.merge!(:octopus_shard => key)
      initialize_adapter(value['adapter'])
      shards[key.to_sym] = connection_pool_for(value, "#{value['adapter']}_connection")

      slave_group_configs = value.select do |_k, v|
        structurally_slave_group? v
      end

      if slave_group_configs.present?
        slave_groups = HashWithIndifferentAccess.new
        slave_group_configs.each do |slave_group_name, slave_configs|
          slaves = HashWithIndifferentAccess.new
          slave_configs.each do |slave_name, slave_config|
            shards[slave_name.to_sym] = connection_pool_for(slave_config, "#{value['adapter']}_connection")
            slaves[slave_name.to_sym] = slave_name.to_sym
          end
          slave_groups[slave_group_name.to_sym] = Octopus::SlaveGroup.new(slaves)
        end
        @shards_slave_groups[key.to_sym] = slave_groups
        @sharded = true
      end
    elsif value.is_a?(Hash)
      @groups[key.to_s] = []

      value.each do |k, v|
        fail 'You have duplicated shard names!' if shards.key?(k.to_sym)

        initialize_adapter(v['adapter'])
        config_with_octopus_shard = v.merge(:octopus_shard => k)

        shards[k.to_sym] = connection_pool_for(config_with_octopus_shard, "#{v['adapter']}_connection")
        @groups[key.to_s] << k.to_sym
      end

      if structurally_slave_group? value
        slaves = Hash[@groups[key.to_s].map { |v| [v, v] }]
        @slave_groups[key.to_sym] = Octopus::SlaveGroup.new(slaves)
      end
    end
  end

  shards[:master] ||= ActiveRecord::Base.connection_pool_without_octopus if Octopus.master_shard == :master
end
shard_name() click to toggle source
# File lib/octopus/proxy_config.rb, line 122
def shard_name
  current_shard.is_a?(Array) ? current_shard.first : current_shard
end
shard_names() click to toggle source

Public: Retrieves names of all loaded shards.

Returns an array of shard names as symbols

# File lib/octopus/proxy_config.rb, line 118
def shard_names
  shards.keys
end
shards_for_group(group) click to toggle source

Public: Retrieves the defined shards for a given group.

Returns an array of shard names as symbols or nil if the group is not defined.

# File lib/octopus/proxy_config.rb, line 130
def shards_for_group(group)
  @groups.fetch(group.to_s, nil)
end

Private Instance Methods

connection_pool_for(config, adapter) click to toggle source
# File lib/octopus/proxy_config.rb, line 215
def connection_pool_for(config, adapter)
  if Octopus.rails4?
    spec = ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(config.dup, adapter )
  else
    name = adapter["octopus_shard"]
    spec = ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(name, config.dup, adapter)
  end

  ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec)
end
initialize_adapter(adapter) click to toggle source
# File lib/octopus/proxy_config.rb, line 244
def initialize_adapter(adapter)
  begin
    require "active_record/connection_adapters/#{adapter}_adapter"
  rescue LoadError
    raise "Please install the #{adapter} adapter: `gem install activerecord-#{adapter}-adapter` (#{$ERROR_INFO})"
  end
end
resolve_string_connection(spec) click to toggle source
# File lib/octopus/proxy_config.rb, line 226
def resolve_string_connection(spec)
  if Octopus.rails41? || Octopus.rails50? || Octopus.rails51?
    resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new({})
    HashWithIndifferentAccess.new(resolver.spec(spec).config)
  else
    resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(spec, {})
    HashWithIndifferentAccess.new(resolver.spec.config)
  end
end
structurally_slave?(config) click to toggle source
# File lib/octopus/proxy_config.rb, line 236
def structurally_slave?(config)
  config.is_a?(Hash) && config.key?('adapter')
end
structurally_slave_group?(config) click to toggle source
# File lib/octopus/proxy_config.rb, line 240
def structurally_slave_group?(config)
  config.is_a?(Hash) && config.values.any? { |v| structurally_slave? v }
end