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
- .activate_shard(shards, &block) ⇒ Object
- .active_shard(group) ⇒ Object
-
.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.
- .ensure_setup ⇒ Object
- .logger ⇒ Object
- .logger=(log) ⇒ Object
- .shard_active_for?(group) ⇒ Boolean
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
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_setup ⇒ Object
93 94 95 |
# File 'lib/data_fabric.rb', line 93 def self.ensure_setup Thread.current[:shards] = {} unless Thread.current[:shards] end |
.logger ⇒ Object
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
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 |