brianmario / mysql2

A modern, simple and very fast Mysql library for Ruby - binding to libmysql
http://github.com/brianmario/mysql2
MIT License
2.25k stars 549 forks source link

Segfault switching between databases #842

Open mahemoff opened 7 years ago

mahemoff commented 7 years ago

I'm trying to setup a multi-db environment. I'm finding any use of ActiveRecord::Base.establish_connection in a callback method causes a segmentation fault (even if it's pointing to the same database that was already connected). I've tried this with pool: 1 and pool: 5 in the config for both databases.

Logs here

Version info: MySQL 2 gem v 0.4.5 Ruby 2.4.1 Rails 5.0.2 MySQL 5.7.17 OSX 10.11.6

mahemoff commented 7 years ago

Further to this, the following also segfaults:

User.transaction { ActiveRecord::Base.establish_connection :test }

ActiveRecord here is already connected to :test. Establishing a connection within a transaction causes the segfault. I think this might be the same as the above segfault, since it occurred within a test using the default Rails' use_transactional_tests setup.

sodabrew commented 7 years ago

That's an interesting bug! I don't like that it crashes, but I do consider that this code path is doomed to failure. The transaction has to be either closed or abandoned if the database of the connection is switched, which should cause the test to fail even if it doesn't crash.

mahemoff commented 7 years ago

I'll take your word that minimal code example is doomed, but in real-world examples, it's hard to track these down and wreaks havoc with CI testing. It usually happens when AR callbacks try to switch database during unit tests. That causes all further tests to abort when running rake test. A regular stack trace would make it easy to diagnose and ensure the full test suite runs.

Separately, is there any other way to switch to a database in the middle of a transaction? Conceptually, it should be perfectly valid to refer to another database in the middle of a transaction, yet I don't see any Rails interface for doing so beyond ActiveRecord::Base.establish_connection. I see some people put establish_connection directly in the class definition, if they are using databases for different classes, but I need to do it dynamically as I am working with multiple databases having the same class.

sodabrew commented 7 years ago

Hmm. USE <DATABASE> is not listed here: https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html

I will continue digging into this.