Class: DbCharmer::Sharding::Method::DbBlockSchemaMap

Inherits:
Object
  • Object
show all
Includes:
DbBlockGroupMapBase
Defined in:
lib/db_charmer/sharding/method/db_block_schema_map.rb

Defined Under Namespace

Classes: Group, Shard

Instance Attribute Summary

Attributes included from DbBlockGroupMapBase

#block_size, #connection, #groups_table, #map_table, #name, #shards_table

Instance Method Summary collapse

Methods included from DbBlockGroupMapBase

#allocate_new_block_for_key, #block_end_for_key, #block_for_key, #block_start_for_key, #clear_group_info_cache, #clear_shard_info_cache, #create_shard_database, #drop_all_shard_databases, #drop_shard_database, #get_cached_block, #group_class, #group_info_by_id, #initialize, #least_loaded_group, #set_cached_block, #shard_class, #shard_connection_config_no_dbname, #shard_for_key, #shard_info_by_group_id, #shard_info_by_id

Instance Method Details

#allocate_new_block_for_key_on_group(key, group) ⇒ Object




71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 71

def allocate_new_block_for_key_on_group(key, group)
  start_id = block_start_for_key(key)
  end_id = block_end_for_key(key)
  # Try to insert a new mapping (ignore duplicate key errors)
  sql = <<-SQL
      INSERT INTO #{map_table}
                   (start_id, end_id, group_id, block_size, created_at, updated_at) VALUES
                   (#{start_id}, #{end_id}, #{group.id}, #{block_size}, NOW(), NOW())
  SQL
  connection.execute(sql, "Allocate new block")

  # Increment the blocks counter on the shard
  group_class.update_counters(group.id, :blocks_count => +1)

  # Retry block search after creation
  block_for_key(key)
end

#connection_name(shard_id) ⇒ Object



35
36
37
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 35

def connection_name(shard_id)
  "db_charmer_db_block_schema_map_#{name}_s%d" % shard_id
end

#create_group(shard, open, enabled) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 112

def create_group(shard, open, enabled)
  # Prepare model
  prepare_shard_models

  # Create the record
  group = Group.create! do |group|
    group.shard_id = shard.id
    group.open     = open
    group.enabled  = enabled
  end

  old_connection = Group.connection
  conn_config = shard_connection_config(shard, group.id)
  Group.switch_connection_to(conn_config)

  schema_name = schema_name(shard.schema_name_prefix, group.id)

  # create schema only if it doesn't already exist
  sql = "SELECT schema_name FROM information_schema.schemata WHERE schema_name='#{schema_name}'"
  existing_schema = Group.connection.execute(sql)
  
  unless existing_schema.first
    sql = "CREATE SCHEMA #{schema_name}"
    Group.connection.execute(sql)
  end
  
  Group.switch_connection_to(old_connection)
end

#create_shard(params) ⇒ Object




91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 91

def create_shard(params)
  params = params.symbolize_keys
  [ :db_host, :db_port, :db_user, :db_name, :schema_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_slave_host = (params[:db_slave_host] || '') if shard.respond_to? :db_slave_host
    shard.db_port = params[:db_port]
    shard.db_user = params[:db_user]
    shard.db_pass = params[:db_pass] || ''
    shard.db_name = params[:db_name]
    shard.schema_name_prefix = params[:schema_name_prefix]
  end
end

#prepare_shard_modelsObject

Prepare model for working with our shards table



150
151
152
153
154
155
156
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 150

def prepare_shard_models
  Shard.switch_connection_to(connection)
  Shard.table_name = shards_table

  Group.switch_connection_to(connection)
  Group.table_name = groups_table
end

#schema_name(schema_name_prefix, group_id) ⇒ Object



39
40
41
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 39

def schema_name(schema_name_prefix, group_id)
  "%s_%05d" % [ schema_name_prefix, group_id ]
end

#shard_connection_config(shard, group_id) ⇒ Object


Create configuration (use mapping connection as a template)



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 45

def shard_connection_config(shard, group_id)
  # Format connection name
  connection_name = connection_name(shard.id)
  schema_name = schema_name(shard.schema_name_prefix, 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
  slave_host = shard.respond_to?(:db_slave_host) ? shard.db_slave_host : ''
  connection.config.clone.merge(
    # Name for the connection factory
    :connection_name => connection_name,
    # Connection params
    :host => shard.db_host,
    :slave_host => slave_host,
    :port => shard.db_port,
    :username => shard.db_user,
    :password => shard.db_pass,
    :database => shard.db_name,
    :schema_name => schema_name,
    :shard_id => shard.id,
    :sharder_name => self.name
  )
end

#shard_connectionsObject



141
142
143
144
145
146
147
# File 'lib/db_charmer/sharding/method/db_block_schema_map.rb', line 141

def shard_connections
  # Find all groups
  prepare_shard_models
  groups = Group.all(:conditions => { :enabled => true }, :include => :shard)
  # Map them to shards
  groups.map { |group| shard_connection_config(group.shard, group.id) }
end