Module: DataFabric

Defined in:
lib/data_fabric.rb,
lib/data_fabric/version.rb,
lib/data_fabric/connection_proxy.rb,
lib/data_fabric/extensions.rb

Overview

DataFabric adds a new level of flexibility to ActiveRecord connection handling. You need to describe the topology for your database infrastructure in your model(s). As with ActiveRecord normally, different models can use different topologies.

class MyHugeVolumeOfDataModel < ActiveRecord::Base

data_fabric :replicated => true, :shard_by => :city

end

There are four supported modes of operation, depending on the options given to the data_fabric method. The plugin will look for connections in your config/database.yml with the following convention:

No connection topology: #environment - this is the default, as with ActiveRecord, e.g. “production”

data_fabric :replicated => true #environment_#role - no sharding, just replication, where role is “master” or “slave”, e.g. “production_master”

data_fabric :shard_by => :city #group_#shard_#environment - sharding, no replication, e.g. “city_austin_production”

data_fabric :replicated => true, :shard_by => :city #group_#shard_#environment_#role - sharding with replication, e.g. “city_austin_production_master”

When marked as replicated, all write and transactional operations for the model go to the master, whereas read operations go to the slave.

Since sharding is an application-level concern, your application must set the shard to use based on the current request or environment. The current shard for a group is set on a thread local variable. For example, you can set the shard in an ActionController around_filter based on the user as follows:

class ApplicationController < ActionController::Base

around_filter :select_shard

private
def select_shard(&action_block)
  DataFabric.activate_shard(:city => @current_user.city, &action_block)
end

end

Defined Under Namespace

Modules: ActiveRecordConnectionMethods, Extensions, Version Classes: ConnectionProxy, PoolProxy, StringProxy

Class Method Summary collapse

Class Method Details

.activate_shard(shards, &block) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/data_fabric.rb', line 52

def self.activate_shard(shards, &block)
  ensure_setup

  # Save the old shard settings to handle nested activation
  old = Thread.current[:shards].dup

  shards.each_pair do |key, value|
    Thread.current[:shards][key.to_s] = value.to_s
  end
  if block_given?
    begin
      yield
    ensure
      Thread.current[:shards] = old
    end
  end
end

.active_shard(group) ⇒ Object

Raises:

  • (ArgumentError)


80
81
82
83
84
85
86
# File 'lib/data_fabric.rb', line 80

def self.active_shard(group)
  raise ArgumentError, 'No shard has been activated' unless Thread.current[:shards]

  shard = Thread.current[:shards][group.to_s]
  raise ArgumentError, "No active shard for #{group}" unless shard
  shard
end

.deactivate_shard(shards) ⇒ Object

For cases where you can’t pass a block to activate_shards, you can clean up the thread local settings by calling this method at the end of processing



73
74
75
76
77
78
# File 'lib/data_fabric.rb', line 73

def self.deactivate_shard(shards)
  ensure_setup
  shards.each do |key, value|
    Thread.current[:shards].delete(key.to_s)
  end
end

.ensure_setupObject



93
94
95
# File 'lib/data_fabric.rb', line 93

def self.ensure_setup
  Thread.current[:shards] = {} unless Thread.current[:shards]
end

.loggerObject



43
44
45
46
# File 'lib/data_fabric.rb', line 43

def self.logger
  devnull = RUBY_PLATFORM =~ /w32/ ? 'nul' : '/dev/null'
  @logger ||= ActiveRecord::Base.logger || Logger.new(devnull)
end

.logger=(log) ⇒ Object



48
49
50
# File 'lib/data_fabric.rb', line 48

def self.logger=(log)
  @logger = log
end

.shard_active_for?(group) ⇒ Boolean

Returns:

  • (Boolean)


88
89
90
91
# File 'lib/data_fabric.rb', line 88

def self.shard_active_for?(group)
  return true unless group
  Thread.current[:shards] and Thread.current[:shards][group.to_s]
end