Class: ActiveRecord::Turntable::Cluster

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/turntable/cluster.rb

Constant Summary collapse

DEFAULT_CONFIG =
{
  "shards" => [],
  "algorithm" => "range",
}.with_indifferent_access

Instance Method Summary collapse

Constructor Details

#initialize(klass, cluster_spec, options = {}) ⇒ Cluster

Returns a new instance of Cluster.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/active_record/turntable/cluster.rb', line 11

def initialize(klass, cluster_spec, options = {})
  @klass = klass
  @config = DEFAULT_CONFIG.merge(cluster_spec)
  @options = options.with_indifferent_access
  @shards = {}.with_indifferent_access

  # setup master shard
  @master_shard = MasterShard.new(klass)

  # setup sequencer
  if (seq = (@options[:seq] || @config[:seq])) && seq[:type] == :mysql
    @seq_shard = SeqShard.new(seq)
  end

  # setup shards
  @config[:shards].each do |spec|
    @shards[spec["connection"]] ||= Shard.new(spec)
  end

  # setup algorithm
  alg_name = "ActiveRecord::Turntable::Algorithm::#{@config["algorithm"].camelize}Algorithm"
  @algorithm = alg_name.constantize.new(@config)

  # setup proxy
  @connection_proxy = ConnectionProxy.new(self, cluster_spec)
end

Instance Method Details

#connection_proxyObject



54
55
56
# File 'lib/active_record/turntable/cluster.rb', line 54

def connection_proxy
  @connection_proxy
end

#klassObject



38
39
40
# File 'lib/active_record/turntable/cluster.rb', line 38

def klass
  @klass
end

#masterObject



42
43
44
# File 'lib/active_record/turntable/cluster.rb', line 42

def master
  @master_shard
end

#select_shard(key) ⇒ Object



65
66
67
68
# File 'lib/active_record/turntable/cluster.rb', line 65

def select_shard(key)
  ActiveSupport::Deprecation.warn "Cluster#select_shard is deprecated, use shard_for() instead.", caller
  shard_for(key)
end

#seqObject



46
47
48
# File 'lib/active_record/turntable/cluster.rb', line 46

def seq
  @seq_shard || @master_shard
end

#shard_for(key) ⇒ Object



58
59
60
61
62
63
# File 'lib/active_record/turntable/cluster.rb', line 58

def shard_for(key)
  @shards[@algorithm.calculate(key)]
rescue
  raise ActiveRecord::Turntable::CannotSpecifyShardError,
  "[#{klass}] cannot select_shard for key:#{key}"
end

#shardsObject



50
51
52
# File 'lib/active_record/turntable/cluster.rb', line 50

def shards
  @shards
end

#shards_transaction(shards = [], options = {}, in_recursion = false, &block) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/active_record/turntable/cluster.rb', line 70

def shards_transaction(shards = [], options = {}, in_recursion = false, &block)
  unless in_recursion
    shards = Array.wrap(shards).dup
    if shards.blank?
      shards = @shards.values.dup
    end
  end
  shard_or_object = shards.shift
  shard = to_shard(shard_or_object)
  if shards.present?
    shard.connection.transaction(options) do
      shards_transaction(shards, options, true, &block)
    end
  else
    shard.connection.transaction(options) do
      block.call
    end
  end
end

#to_shard(shard_or_object) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/active_record/turntable/cluster.rb', line 90

def to_shard(shard_or_object)
  case shard_or_object
  when ActiveRecord::Turntable::Shard
    shard_or_object
  when ActiveRecord::Base
    shard_or_object.turntable_shard
  when Numeric, String
    shard_for(shard_or_object)
  when Symbol
    shards[shard_or_object]
  else
    binding.pry
    raise ActiveRecord::Turntable::TurntableError,
            "transaction cannot call to object: #{shard_or_object}"
  end
end

#weighted_shards(key = nil) ⇒ Object



107
108
109
110
111
112
# File 'lib/active_record/turntable/cluster.rb', line 107

def weighted_shards(key = nil)
  key ||= @klass.current_sequence
  Hash[@algorithm.calculate_used_shards_with_weight(key).map do |k,v|
    [@shards[k], v]
  end]
end