Module: DataFabric

Defined in:
lib/data_fabric.rb,
lib/data_fabric/ar20.rb,
lib/data_fabric/version.rb,
lib/data_fabric/ar22.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, StringProxy

Class Method Summary collapse

Class Method Details

.activate_shard(shards, &block) ⇒ Object


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/data_fabric.rb', line 57

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)

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

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

  returning(Thread.current[:shards][group.to_s]) do |shard|
    raise ArgumentError, "No active shard for #{group}" unless shard
  end
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


78
79
80
81
82
83
# File 'lib/data_fabric.rb', line 78

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

.ensure_setupObject


98
99
100
# File 'lib/data_fabric.rb', line 98

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

.initObject


45
46
47
48
49
50
51
52
53
54
55
# File 'lib/data_fabric.rb', line 45

def self.init
  logger = ActiveRecord::Base.logger unless logger
  log { "Loading data_fabric #{DataFabric::Version::STRING} with ActiveRecord #{ActiveRecord::VERSION::STRING}" }

  if ActiveRecord::VERSION::STRING < '2.2.0'
    require 'data_fabric/ar20'
  else
    require 'data_fabric/ar22'
  end
  ActiveRecord::Base.send(:include, DataFabric::Extensions)
end

.log(level = Logger::INFO, &block) ⇒ Object


102
103
104
# File 'lib/data_fabric.rb', line 102

def self.log(level=Logger::INFO, &block)
  logger && logger.add(level, &block)
end

.shard_active_for?(group) ⇒ Boolean

Returns:

  • (Boolean)

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

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