module DbCharmer
This class is used to automatically generate small abstract ActiveRecord
classes that would then be used as a source of database connections for DbCharmer
magic. This way we do not need to re-implement all the connection establishing code that ActiveRecord
already has and we make our code less dependant on Rails versions.
Simple proxy that sends all method calls to a real database connection
This is a more sophisticated sharding method based on a two layer database-backed blocks map that holds block-shard associations. Record blocks are mapped to tablegroups and groups are mapped to shards.
It automatically creates new blocks for new keys and assigns them to existing groups. Warning: make sure to create at least one shard and one group before inserting any records.
This is a more sophisticated sharding method based on a database-backed blocks map that holds block-shard associations. It automatically creates new blocks for new keys and assigns them to shards.
This is a simple proxy class used as a default connection on sharded models
The idea is to proxy all utility method calls to a real connection (set by the set_real_connection
method when we switch shards) and fail on real database querying calls forcing users to switch shard connections.
Public Class Methods
# File lib/db_charmer.rb, line 56 def self.connections_should_exist? !! connections_should_exist end
# File lib/db_charmer/force_slave_reads.rb, line 2 def self.current_controller Thread.current[:db_charmer_current_controller] end
# File lib/db_charmer/force_slave_reads.rb, line 6 def self.current_controller=(val) Thread.current[:db_charmer_current_controller] = val end
Returns current environment name based on Rails or Rack environment variables
# File lib/db_charmer.rb, line 42 def self.detect_environment return Rails.env if running_with_rails? ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default' end
# File lib/db_charmer.rb, line 68 def self.enable_controller_magic! ::ActionController::Base.extend(DbCharmer::ActionController::ForceSlaveReads::ClassMethods) ::ActionController::Base.send(:include, DbCharmer::ActionController::ForceSlaveReads::InstanceMethods) end
# File lib/db_charmer/force_slave_reads.rb, line 45 def self.force_slave_reads raise ArgumentError, "No block given" unless block_given? old_forced_slave_reads = self.forced_slave_reads_setting begin self.forced_slave_reads_setting = true yield ensure self.forced_slave_reads_setting = old_forced_slave_reads end end
# File lib/db_charmer/force_slave_reads.rb, line 20 def self.force_slave_reads? # If global force slave reads is requested, do it return true if Thread.current[:db_charmer_forced_slave_reads] # If not, try to use current controller to decide on this return false unless current_controller.respond_to?(:force_slave_reads?) slave_reads = current_controller.force_slave_reads? logger.debug("Using controller to figure out if slave reads should be forced: #{slave_reads}") return slave_reads end
# File lib/db_charmer/force_slave_reads.rb, line 11 def self.forced_slave_reads_setting Thread.current[:db_charmer_forced_slave_reads] end
# File lib/db_charmer/force_slave_reads.rb, line 15 def self.forced_slave_reads_setting=(val) Thread.current[:db_charmer_forced_slave_reads] = val end
# File lib/db_charmer/with_remapped_databases.rb, line 16 def self.hijack_new_classes? !! Thread.current[:db_charmer_hijack_new_classes] end
# File lib/db_charmer.rb, line 61 def self.logger return Rails.logger if running_with_rails? @@logger ||= Logger.new(STDERR) end
Used in all Rails2-specific places
# File lib/db_charmer.rb, line 26 def self.rails2? ::ActiveRecord::VERSION::MAJOR == 2 end
Used in all Rails3.1-specific places
# File lib/db_charmer.rb, line 21 def self.rails31? rails3? && ::ActiveRecord::VERSION::MINOR >= 1 end
Detect broken Rails version
# File lib/db_charmer.rb, line 31 def self.rails324? ActiveRecord::VERSION::STRING == '3.2.4' end
# File lib/db_charmer.rb, line 16 def self.rails3? ::ActiveRecord::VERSION::MAJOR > 2 end
# File lib/db_charmer.rb, line 37 def self.running_with_rails? defined?(Rails) && Rails.respond_to?(:env) end
# File lib/db_charmer/force_slave_reads.rb, line 33 def self.with_controller(controller) raise ArgumentError, "No block given" unless block_given? logger.debug("Setting current controller for db_charmer: #{controller.class.name}") self.current_controller = controller yield ensure logger.debug('Clearing current controller for db_charmer') self.current_controller = nil end
# File lib/db_charmer/with_remapped_databases.rb, line 2 def self.with_remapped_databases(mappings, &proc) old_mappings = ::ActiveRecord::Base.db_charmer_database_remappings begin ::ActiveRecord::Base.db_charmer_database_remappings = mappings if mappings[:master] || mappings['master'] with_all_hijacked(&proc) else proc.call end ensure ::ActiveRecord::Base.db_charmer_database_remappings = old_mappings end end
Private Class Methods
# File lib/db_charmer/with_remapped_databases.rb, line 22 def self.with_all_hijacked old_hijack_new_classes = Thread.current[:db_charmer_hijack_new_classes] begin Thread.current[:db_charmer_hijack_new_classes] = true subclasses_method = DbCharmer.rails3? ? :descendants : :subclasses ::ActiveRecord::Base.send(subclasses_method).each do |subclass| subclass.hijack_connection! end yield ensure Thread.current[:db_charmer_hijack_new_classes] = old_hijack_new_classes end end