# 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. # module DbCharmer module Sharding module Method class DbBlockGroupMap include DbBlockGroupMapBase # Shard connection info model class Shard < ::ActiveRecord::Base validates_presence_of :db_host validates_presence_of :db_port validates_presence_of :db_user validates_presence_of :db_pass validates_presence_of :db_name_prefix has_many :groups, :class_name => 'DbCharmer::Sharding::Method::DbBlockGroupMap::Group' end # Table group info model class Group < ::ActiveRecord::Base validates_presence_of :shard_id belongs_to :shard, :class_name => 'DbCharmer::Sharding::Method::DbBlockGroupMap::Shard' end #--------------------------------------------------------------------------------------------------------------- # Create configuration (use mapping connection as a template) def shard_connection_config(shard, group_id) # Format connection name shard_name = "db_charmer_db_block_group_map_#{name}_s%d_g%d" % [ shard.id, group_id] # Here we get the mapping connection's configuration # They do not expose configs so we hack in and get the instance var # FIXME: Find a better way, maybe move config method to our ar extenstions connection.instance_variable_get(:@config).clone.merge( # Name for the connection factory :connection_name => shard_name, # Connection params :host => shard.db_host, :port => shard.db_port, :username => shard.db_user, :password => shard.db_pass, :database => group_database_name(shard, group_id) ) end def group_database_name(shard, group_id) "%s_%05d" % [ shard.db_name_prefix, group_id ] end #--------------------------------------------------------------------------------------------------------------- def create_shard(params) params = params.symbolize_keys [ :db_host, :db_port, :db_user, :db_pass, :db_name_prefix ].each do |arg| raise ArgumentError, "Missing required parameter: #{arg}" unless params[arg] end # Prepare model prepare_shard_models # Create the record Shard.create! do |shard| shard.db_host = params[:db_host] shard.db_port = params[:db_port] shard.db_user = params[:db_user] shard.db_pass = params[:db_pass] shard.db_name_prefix = params[:db_name_prefix] end end def create_group(shard_id, open, enabled) # Prepare model prepare_shard_models # Create the record Group.create! do |group| group.shard_id = shard_id group.open = open group.enabled = enabled end end end end end end