Class: ActiveRecord::ConnectionAdapters::MysqlReplicationAdapter

Inherits:
MysqlAdapter
  • Object
show all
Defined in:
lib/mysql_replication_adapter.rb

Overview

The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/).

Options:

  • :host -- Defaults to localhost
  • :port -- Defaults to 3306
  • :socket -- Defaults to /tmp/mysql.sock
  • :username -- Defaults to root
  • :password -- Defaults to nothing
  • :database -- The name of the database. No default, must be provided.
  • :sslkey -- Necessary to use MySQL with an SSL connection
  • :sslcert -- Necessary to use MySQL with an SSL connection
  • :sslcapath -- Necessary to use MySQL with an SSL connection
  • :sslcipher -- Necessary to use MySQL with an SSL connection

By default, the MysqlAdapter will consider all columns of type tinyint(1) as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your environment.rb file:

ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false

Instance Method Summary collapse

Constructor Details

#initialize(connection, logger, connection_options, config) ⇒ MysqlReplicationAdapter

@@emulate_booleans = true cattr_accessor :emulate_booleans

LOST_CONNECTION_ERROR_MESSAGES = [ "Server shutdown in progress", "Broken pipe", "Lost connection to MySQL server during query", "MySQL server has gone away" ]



60
61
62
63
64
# File 'lib/mysql_replication_adapter.rb', line 60

def initialize(connection, logger, connection_options, config)
  @master = @clones = nil
  @retries = config[:retries]
  super(connection, logger, connection_options, config)
end

Instance Method Details

#adapter_nameObject

:nodoc:



66
67
68
# File 'lib/mysql_replication_adapter.rb', line 66

def adapter_name #:nodoc:
  'MySQLReplication'
end

#disconnect!Object



94
95
96
97
98
99
100
101
# File 'lib/mysql_replication_adapter.rb', line 94

def disconnect!
  @master.close rescue nil
  if @clones
    @clones.each do |clone|
      clone.close rescue nil
    end
  end
end

#ensure_masterObject

This method raises an exception if the current connection is a clone. It is called inside all of the methods that typically cause database writes. This keeps the developer from doing any writes when inside a slave query block.

Raises:



90
91
92
# File 'lib/mysql_replication_adapter.rb', line 90

def ensure_master
  raise CannotWriteToSlave, "You attempted to perform a write operation inside a slave-balanced read block." unless @connection == @master
end

#execute(sql, name = nil) ⇒ Object

DATABASE STATEMENTS ======================================



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/mysql_replication_adapter.rb', line 106

def execute(sql, name = nil) #:nodoc:
  retries = 0
  log(sql, "#{name} against #{@connection.host_info}") do
    @connection.query(sql) 
  end
rescue Mysql::Error => ex
  if ex.message =~ /MySQL server has gone away/
    if @retries && retries < @retries
      retries += 1
      disconnect!
      connect
      retry
    else
      raise
    end
  else
    raise
  end
rescue ActiveRecord::StatementInvalid => exception
  if exception.message.split(":").first =~ /Packets out of order/
    raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information.  If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
  else
    raise
  end
end

#insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) ⇒ Object

:nodoc:



132
133
134
135
136
# File 'lib/mysql_replication_adapter.rb', line 132

def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
  ensure_master
  execute(sql, name = nil)
  id_value || @connection.insert_id
end

#load_balance_queryObject

the magic load_balance method



71
72
73
74
75
76
77
# File 'lib/mysql_replication_adapter.rb', line 71

def load_balance_query
  old_connection = @connection
  @connection = select_clone
  yield
ensure
  @connection = old_connection
end

#select_cloneObject

choose a random clone to use for the moment



80
81
82
83
84
85
# File 'lib/mysql_replication_adapter.rb', line 80

def select_clone
  # if we happen not to be connected to any clones, just use the master
  return @master if @clones.nil? || @clones.empty? 
  # return a random clone
  return @clones[rand(@clones.size)]
end

#update(sql, name = nil) ⇒ Object

:nodoc:



138
139
140
141
142
# File 'lib/mysql_replication_adapter.rb', line 138

def update(sql, name = nil) #:nodoc:
  ensure_master
  execute(sql, name)
  @connection.affected_rows
end