Showing preview only (338K chars total). Download the full file or copy to clipboard to get everything.
Repository: kovyrin/db-charmer
Branch: master
Commit: 0c71563472ed
Files: 160
Total size: 297.8 KB
Directory structure:
gitextract_9iqagwm9/
├── .gitignore
├── .travis.yml
├── CHANGES
├── LICENSE
├── Makefile
├── README.rdoc
├── Rakefile
├── ci_build
├── db-charmer.gemspec
├── init.rb
├── issues/
│ └── issues-as-of-2014-11-14.json
├── lib/
│ ├── db_charmer/
│ │ ├── action_controller/
│ │ │ └── force_slave_reads.rb
│ │ ├── active_record/
│ │ │ ├── association_preload.rb
│ │ │ ├── class_attributes.rb
│ │ │ ├── connection_switching.rb
│ │ │ ├── db_magic.rb
│ │ │ ├── migration/
│ │ │ │ └── multi_db_migrations.rb
│ │ │ ├── multi_db_proxy.rb
│ │ │ └── sharding.rb
│ │ ├── connection_factory.rb
│ │ ├── connection_proxy.rb
│ │ ├── core_extensions.rb
│ │ ├── force_slave_reads.rb
│ │ ├── rails2/
│ │ │ ├── abstract_adapter/
│ │ │ │ └── log_formatting.rb
│ │ │ └── active_record/
│ │ │ ├── master_slave_routing.rb
│ │ │ └── named_scope/
│ │ │ └── scope_proxy.rb
│ │ ├── rails3/
│ │ │ ├── abstract_adapter/
│ │ │ │ └── connection_name.rb
│ │ │ └── active_record/
│ │ │ ├── log_subscriber.rb
│ │ │ ├── master_slave_routing.rb
│ │ │ ├── relation/
│ │ │ │ └── connection_routing.rb
│ │ │ └── relation_method.rb
│ │ ├── rails31/
│ │ │ └── active_record/
│ │ │ ├── migration/
│ │ │ │ └── command_recorder.rb
│ │ │ └── preloader/
│ │ │ ├── association.rb
│ │ │ └── has_and_belongs_to_many.rb
│ │ ├── railtie.rb
│ │ ├── sharding/
│ │ │ ├── connection.rb
│ │ │ ├── method/
│ │ │ │ ├── db_block_group_map.rb
│ │ │ │ ├── db_block_map.rb
│ │ │ │ ├── hash_map.rb
│ │ │ │ └── range.rb
│ │ │ ├── method.rb
│ │ │ └── stub_connection.rb
│ │ ├── sharding.rb
│ │ ├── tasks/
│ │ │ └── databases.rake
│ │ ├── version.rb
│ │ └── with_remapped_databases.rb
│ └── db_charmer.rb
├── test-project/
│ ├── .gitignore
│ ├── .rspec
│ ├── Gemfile
│ ├── Rakefile
│ ├── TODO
│ ├── app/
│ │ ├── controllers/
│ │ │ ├── application_controller.rb
│ │ │ └── posts_controller.rb
│ │ ├── helpers/
│ │ │ └── application_helper.rb
│ │ ├── models/
│ │ │ ├── avatar.rb
│ │ │ ├── car.rb
│ │ │ ├── categories_posts.rb
│ │ │ ├── category.rb
│ │ │ ├── comment.rb
│ │ │ ├── event.rb
│ │ │ ├── ford.rb
│ │ │ ├── house.rb
│ │ │ ├── log_record.rb
│ │ │ ├── post.rb
│ │ │ ├── range_sharded_model.rb
│ │ │ ├── toyota.rb
│ │ │ └── user.rb
│ │ └── views/
│ │ ├── layouts/
│ │ │ └── application.html.erb
│ │ └── posts/
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── config/
│ │ ├── application.rb
│ │ ├── boot.rb
│ │ ├── database.yml.example
│ │ ├── environment.rb
│ │ ├── environments/
│ │ │ └── test.rb
│ │ ├── initializers/
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── db_charmer.rb
│ │ │ ├── secret_token.rb
│ │ │ ├── session_store.rb
│ │ │ └── sharding.rb
│ │ ├── locales/
│ │ │ └── en.yml
│ │ └── routes.rb
│ ├── db/
│ │ ├── create_databases.sql
│ │ ├── migrate/
│ │ │ ├── 20090810013829_create_log_records.rb
│ │ │ ├── 20090810013922_create_posts.rb
│ │ │ ├── 20090810221944_create_users.rb
│ │ │ ├── 20100305234245_create_categories.rb
│ │ │ ├── 20100305234340_create_categories_posts.rb
│ │ │ ├── 20100305235831_create_avatars.rb
│ │ │ ├── 20100328201317_create_sharding_map_tables.rb
│ │ │ ├── 20100330180517_create_event_tables.rb
│ │ │ ├── 20100817191548_create_cars.rb
│ │ │ └── 20111005193941_create_comments.rb
│ │ ├── seeds.rb
│ │ └── sharding.sql
│ └── spec/
│ ├── controllers/
│ │ └── posts_controller_spec.rb
│ ├── fixtures/
│ │ ├── avatars.yml
│ │ ├── categories.yml
│ │ ├── categories_posts.yml
│ │ ├── comments.yml
│ │ ├── event_shards_info.yml
│ │ ├── event_shards_map.yml
│ │ ├── log_records.yml
│ │ ├── posts.yml
│ │ └── users.yml
│ ├── integration/
│ │ └── multi_threading_spec.rb
│ ├── models/
│ │ ├── avatar_spec.rb
│ │ ├── cars_spec.rb
│ │ ├── categories_posts_spec.rb
│ │ ├── category_spec.rb
│ │ ├── comment_spec.rb
│ │ ├── event_spec.rb
│ │ ├── log_record_spec.rb
│ │ ├── post_spec.rb
│ │ ├── range_sharded_model_spec.rb
│ │ └── user_spec.rb
│ ├── sharding/
│ │ ├── connection_spec.rb
│ │ ├── method/
│ │ │ ├── db_block_map_spec.rb
│ │ │ ├── hash_map_spec.rb
│ │ │ └── range_spec.rb
│ │ └── sharding_spec.rb
│ ├── spec_helper.rb
│ ├── support/
│ │ └── rails31_stub_connection.rb
│ └── unit/
│ ├── abstract_adapter/
│ │ └── log_formatting_spec.rb
│ ├── action_controller/
│ │ └── force_slave_reads_spec.rb
│ ├── active_record/
│ │ ├── association_preload_spec.rb
│ │ ├── association_proxy_spec.rb
│ │ ├── class_attributes_spec.rb
│ │ ├── connection_switching_spec.rb
│ │ ├── db_magic_spec.rb
│ │ ├── master_slave_routing_spec.rb
│ │ ├── migration/
│ │ │ └── multi_db_migrations_spec.rb
│ │ ├── named_scope/
│ │ │ └── named_scope_spec.rb
│ │ └── relation_spec.rb
│ ├── connection_factory_spec.rb
│ ├── connection_proxy_spec.rb
│ ├── db_charmer_spec.rb
│ ├── multi_db_proxy_spec.rb
│ └── with_remapped_databases_spec.rb
└── test-project-2.x/
├── Gemfile
├── Rakefile
├── config/
│ ├── boot.rb
│ ├── database.yml.example
│ ├── environment.rb
│ ├── environments/
│ │ └── test.rb
│ ├── initializers/
│ │ ├── backtrace_silencers.rb
│ │ ├── db_charmer.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── new_rails_defaults.rb
│ │ ├── session_store.rb
│ │ └── sharding.rb
│ ├── locales/
│ │ └── en.yml
│ ├── preinitializer.rb
│ └── routes.rb
├── script/
│ └── console
└── spec/
├── spec.opts
└── spec_helper.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
doc
pkg
.DS_Store
_site
.idea
================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
- 1.8.7
- 1.9.3
- 2.0.0
env:
- RAILS_VERSION=2.x
- RAILS_VERSION=3.0.20
- RAILS_VERSION=3.1.12
- RAILS_VERSION=3.2.3
- RAILS_VERSION=3.2.15
- RAILS_VERSION=3.2.15 DB_CHARMER_GEM=1.9.0
notifications:
recipients:
- alexey@kovyrin.net
script: ./ci_build
# Whitelist branches to test
branches:
only:
- master
- rails4
# Build matrix configuration
matrix:
exclude:
# Do not run Rails 2.x tests on ruby 1.9
- rvm: 1.9.3
env: RAILS_VERSION=2.x
# Do not run Rails 2.x tests on ruby 2.0
- rvm: 2.0.0
env: RAILS_VERSION=2.x
# Do not run Rails 3.0 tests on ruby 2.0
- rvm: 2.0.0
env: RAILS_VERSION=3.0.20
# Do not run Rails 3.1 tests on ruby 2.0
- rvm: 2.0.0
env: RAILS_VERSION=3.1.12
# Do not run early Rails 3.2 tests on ruby 2.0
- rvm: 2.0.0
env: RAILS_VERSION=3.2.3
================================================
FILE: CHANGES
================================================
1.9.1 (2014-11-14):
The project has been suspended. No updates will be provided and no Rails versions
beyond 3.2.x will be supported.
For more information please check out this blog post: http://kovyrin.net/2014/11/14/dbcharmer-suspended/
----------------------------------------------------------------------------------------
1.9.0 (2013-10-09):
Most of the major changes in this version are related to our initial push towards making
DbCharmer thread-safe and making sure it works correctly in multi-threaded environments.
Please note, that even though we now test DbCharmer in multi-threaded environments, we still
consider multi-threaded support experimental.
Bug fix: Improved Rails environment detection (sometimes DbCharmer would use
Rails-specific code while running in non-rails projects).
Bug fix: Make sure on_db() method could restore original connection after an exception is
raised from a DB driver during connection switching (Thanks to Dmytro Shteflyuk for finding
the issue and helping with debugging).
This is the first release that does not have a really strict constraint for point-releases
within the Rails 3.2.x branch.
----------------------------------------------------------------------------------------
1.8.4 (2013-03-18):
Bumped up rails dependencies up to 3.2.13.
----------------------------------------------------------------------------------------
1.8.3 (2013-02-11):
Bumped up rails dependencies up to 3.2.12.
----------------------------------------------------------------------------------------
1.8.2 (2013-01-11):
Bumped up rails dependencies up to 3.2.11.
----------------------------------------------------------------------------------------
1.8.1 (2013-01-02):
Bumped up rails dependencies up to 3.2.10.
----------------------------------------------------------------------------------------
1.8.0 (2012-11-12):
Added support for Rails versions up to 3.2.9. Please note, that Rails 3.2.4 is not officially
supported. Your code may work on that version, but no bug reports will be accepted about this
version.
Tests for DbCharmer have been moved to the gem repository to make Travis-CI integration more
stable. We do not put test files into the gem inself so it should not be a problem for most
of the users. If you still use db-charmer as a plugin, please switch to gem mode.
----------------------------------------------------------------------------------------
1.7.1 (2012-04-22):
Beta feature: Rails 3.1 and 3.2 support
Thanks to the community (and Eugene Pimenov aka @libc in particular) we now have support
for Rails versions up to 3.2.1, including new migrations classes.
----------------------------------------------------------------------------------------
1.7.0 (2011-08-29):
Beta feature: Rails 3 support
Beta feature: Added force_slave_reads functionality. Now we could have models with slaves
that are not used by default, but could be turned on globally (per-controller or per-action).
Heavily reorganized the source code to match Rails code structure (class names, etc). This should
make it much easier for other contributors to work with the code.
Added smarter environment detection (using Rails.env, RAILS_ENV or RACK_ENV).
Changed dependencies a bit: instead of depending on rails, we now require specific components
(ActiveRecord, ActiveSupport, etc) + we do not require blankslate gem anymore.
Bugfixes: Fix for N+1 queries when accessing shard_info for db_block_group_map sharding method.
----------------------------------------------------------------------------------------
1.6.17-19 (2011-04-25):
Bugfixes: Do not touch database for sharded models until we really need to. Before 1.6.17
if a database server was dead and there were any other connection issues, class loading
in Ruby would be broken and sharded model class would not be initialized.
----------------------------------------------------------------------------------------
1.6.14 (2011-01-09):
Bugfixes: We do not support Rails 3, and now we prohibit any versions but 2.2 and 2.3 from
being used with db-charmer gem.
----------------------------------------------------------------------------------------
1.6.13 (2010-08-17):
Starting with this version we use Rails.env instead of RAILS_ENV to auto-detect rails
environment. If you use DbCharmer in non-rails project, please set DbCharmer.env manually.
Bugfixes: Thanks to Eric Lindvall we now allow connection names that have symbols ruby
wouldn't like for class names.
----------------------------------------------------------------------------------------
1.6.12 (2010-05-09):
Starting with this version we use Rails.cache (memcache or whatever you use in your project)
to cache sharding blocks information.
Bugfixes: Thanks to Allen Madsen (github user blatyo) we've fixed a few minor issues in
database connections handling.
----------------------------------------------------------------------------------------
1.6.11 (2010-04-16):
Bugfix: Change the way we allocate sharding blocks in block map sharding method to
prevent race-conditions from happening on block to shard assignments.
Breaking change: We require connections to exist by default in all connection factory
methods. If you need old behavior, pass should_exist=false explicitly.
----------------------------------------------------------------------------------------
1.6.10 (2010-04-09):
Multi-Db migrations changed. Now it is possible to call ActiveRecord::Migration.db_magic
and specify default migration connection that would be used by all migrations without
excplicitly switched connections.
----------------------------------------------------------------------------------------
1.6.9 (2010-04-08):
Bugfix release: now DbCharmer works without Rails.
----------------------------------------------------------------------------------------
1.6.7 (2010-04-07):
Changed the way we handle associations in on_db(:foo).find(:include) calls. Now we
switch association's connection only if its default connection is the same as the
master model's connection (not more "table does not exist" problems I hope).
----------------------------------------------------------------------------------------
1.6.5 (2010-04-05):
Bugfix release: Fixed :connection vs :slave in db_magic behaviour. Model.on_master should
run queries on the master, not on AR's default connection.
----------------------------------------------------------------------------------------
1.6.4 (2010-04-05):
Default behaviour changed: DbCharmer.connections_should_exist is true in all environments
by default. Old default behaviour was too misleading for many developers.
----------------------------------------------------------------------------------------
1.6.3 (2010-04-03):
Bugfix release: Modified stub connection initialization code to set default connections
for sharded models using shards enumeration or default shard features of sharding methods.
----------------------------------------------------------------------------------------
1.6.2 (2010-04-03):
Bugfix release: Modified our stub connection used on sharded models to fail on db-calling
methods only. Proxy the rest to a real shard connection. Another bug fixed in db_block_map
sharding method: we didn't increment block counters when assigning blocks to shards.
----------------------------------------------------------------------------------------
1.6.1 (2010-03-31):
Breaking change from now on all connection-switching methods (both in migrations and in
models) are controlled by a single option DbCharmer.connections_should_exist. This
option is false by default in all non-production environments. Check out README for
more details.
----------------------------------------------------------------------------------------
1.6.0 (2010-03-31):
The major (and arguably the only noticeable) change in this version is our simple database
sharding support. The feature is still in alpha stage and should not be used in production
without complete understanding of the principles of its work.
----------------------------------------------------------------------------------------
1.5.5 (2010-03-15):
Thanks to ngmoco.com (http://github.com/ngmoco) now DbCharmer supports one more use-case
for multi-db migrations. Now you can run the same migration on many databases at once.
For example, the following migration would create test_table on all three shard databases:
class MultiDbTest < ActiveRecord::Migration
db_magic :connections => [ :shard01, :shard02, :shard03 ]
def self.up
create_table :test_table do |t|
t.string :test_string
t.timestamps
end
end
def self.down
drop_table :test_table
end
end
----------------------------------------------------------------------------------------
1.5.4 (2010-03-12):
Added DbCharmer.with_remapped_databases, so that you can change the connection for
many models simultaneously, and implicitly. Very useful for work where you want to use
a particular slave for a whole range of database access.
----------------------------------------------------------------------------------------
1.5.3 (2010-03-10):
Few changes:
* Colorized connection names in the logs for development mode
* We do not log connection names when connection does not exist
----------------------------------------------------------------------------------------
1.5.1 (2010-03-06):
In this version we've added support for connection names logging in Rails queries log.
New log records have [connection_name] prefix for all queries that are executed on
non-standard connections:
[logs] LogRecord Columns (1.1ms) SHOW FIELDS FROM `log_records`
[logs] User Delete all (0.1ms) DELETE FROM `users`
[slave01] User Load (0.2ms) SELECT * FROM `users` WHERE (`users`.`login` = 'foo')
----------------------------------------------------------------------------------------
1.4.6 -> 1.5.0 (2010-03-05):
Major change in this version of DbCharmer is association preload support. For example,
let's say we have a schema:
class Post < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
Now, if we have the following call in our code:
User.on_db(:foo).all(:include => :posts)
In 1.4.6 it would load the users from connection :foo and posts from the
default connection, which is not what we would expect from this line of code.
So, starting 1.5.0 all finder calls on models having :include parameter would
switch associated models' connections to the same connection as the main model
in the call.
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2011, Oleksiy Kovyrin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: Makefile
================================================
doc/files/README_rdoc.html: README.rdoc
rdoc README.rdoc
================================================
FILE: README.rdoc
================================================
= WARNING: The Project Has Been Suspended
Please note, that this project has been suspended. No updates will be provided and no Rails versions
beyond 3.2.x will be supported. For more information please check out this blog post: http://kovyrin.net/2014/11/14/dbcharmer-suspended/
= DB Charmer - ActiveRecord Connection Magic Plugin
+DbCharmer+ is a simple yet powerful plugin for ActiveRecord that significantly extends its ability to work with
multiple databases and/or database servers. The major features we add to ActiveRecord are:
1. Simple management for AR model connections (+switch_connection_to+ method)
2. Switching of default AR model connections to separate servers/databases
3. Ability to easily choose where your query should go (<tt>Model.on_*</tt> methods family)
4. Automated master/slave queries routing (selects go to a slave, updates handled by the master).
5. Multiple database migrations with very flexible query routing controls.
6. Simple database sharding functionality with multiple sharding methods (value, range, mapping table).
For more information on the project, you can check out our web site at http://kovyrin.github.io/db-charmer/.
== Installation
There are two options when approaching +DbCharmer+ installation:
* using the gem (recommended and the only way of using it with Rails 3.2+)
* install as a Rails plugin (works in Rails 2.x only)
To install as a gem, add this to your Gemfile:
gem 'db-charmer', :require => 'db_charmer'
To install +DbCharmer+ as a Rails plugin use the following command:
./script/plugin install git://github.com/kovyrin/db-charmer.git
_Notice_: If you use +DbCharmer+ in a non-rails project, you may need to set <tt>DbCharmer.env</tt> to a correct value
before using any of its connection management methods. Correct value here is a valid <tt>database.yml</tt>
first-level section name.
== Documentation/Questions
For more information about the library, please visit our site at http://dbcharmer.net.
If you need more defails on DbCharmer internals, please check out the source code. All the plugin's
code is ~100% covered with tests. The project located in <tt>test-project</tt> directory has unit
tests for all or, at least, the most actively used code paths.
If you have any questions regarding this project, you could contact the author using
the DbCharmer Users Group mailing list:
- Group Info: http://groups.google.com/group/db-charmer
- Subscribe using the info page or by sending an email to mailto:db-charmer-subscribe@googlegroups.com
== What Ruby and Rails implementations does it work for?
We have a continuous integration setup for this gem on with Rails 2.3, 3.0, 3.1 and 3.2 using a few
different versions of Ruby.
CI is running on TravisCI.org: https://travis-ci.org/kovyrin/db-charmer
Build status is: {<img src="https://secure.travis-ci.org/kovyrin/db-charmer.png?branch=master" alt="Build Status: Rails 3.x" />}[https://travis-ci.org/kovyrin/db-charmer]
At the moment we have the following build matrix:
* Rails versions:
- 2.3
- 3.0
- 3.1
- 3.2
* Ruby versions:
- 1.8.7
- 1.9.3 (Rails 3.0+ only)
- 2.0.0 (Rails 3.2+ only)
* Databases:
- MySQL
In addition to CI testing, this gem is used in production on Scribd.com (one of the largest RoR
sites in the world) with Ruby Enterprise Edition and Rails 2.2, Rails 2.3, Sinatra and plain
Rack applications.
Starting with version 1.8.0 we support Rails versions 3.2.8 and higher. Please note, that Rails 3.2.4
is not officially supported. Your code may work on that version, but no bug reports will be
accepted about this version.
== Is it Thread-Safe?
Starting with version 1.9.0 we have started working on making the code thread-safe and making sure
DbCharmer works correctly in multi-threaded environments. At this moment we consider multi-threaded
mode experimental. If you use it and it works for you - please let us know, if it does not - please
make sure to file a ticket so that we could improve the code and make it work in your situation.
== Who are the authors?
This plugin has been created in Scribd.com for our internal use and then the sources were opened for
other people to use. Most of the code in this package has been developed by Oleksiy Kovyrin for
Scribd.com and is released under the MIT license. For more details, see the LICENSE file.
Other contributors who have helped with the development of this library are (alphabetically ordered):
* Allen Madsen
* Andrew Geweke
* Ashley Martens
* Cauê Guerra
* David Dai
* Dmytro Shteflyuk
* Eric Lindvall
* Eugene Pimenov
* Jonathan Viney
* Gregory Man
* Michael Birk
* Tyler McMullen
================================================
FILE: Rakefile
================================================
require 'rake'
require 'bundler'
Bundler::GemHelper.install_tasks
================================================
FILE: ci_build
================================================
#!/bin/bash
# Making the script more robust
set -e # Exit on errors
set -u # Exit on uninitialized variables
RAILS_VERSION=${RAILS_VERSION:-}
if [ "$RAILS_VERSION" == "" ]; then
echo "Please specify rails version using RAILS_VERSION environment variable!"
exit 1
fi
# Change directory according to the rails version
if [ "$RAILS_VERSION" == "2.x" ]; then
# Downgrade rubygems because rails 2.3 does not work on 2.0+
gem update --system 1.8.25
cd test-project-2.x
else
cd test-project
fi
# Print version info
echo "-----------------------------------------------------------------------------------------------------------------"
echo " * Running specs for Rails version $RAILS_VERSION..."
echo " * Ruby version: `ruby --version`"
echo " * Rubygems version: `gem --version`"
echo " * DbCharmer gem version: '${DB_CHARMER_GEM:-trunk}'"
echo "-----------------------------------------------------------------------------------------------------------------"
# Test environment
export RAILS_ENV=test
# Configure database access
cp -f config/database.yml.example config/database.yml
# Create databases and sharding tables
mysql -u root < db/create_databases.sql
mysql -u root db_charmer_sandbox_test < db/sharding.sql
# Install gems
rm -f Gemfile.lock
bundle install
# Run migrations
bundle exec rake --trace db:migrate
# Run the build and return its exit code
if [ "$RAILS_VERSION" == "2.x" ]; then
exec bundle exec spec -p '/*/**/*_spec.rb' -cbfs spec
else
exec bundle exec rspec -cbfs spec
fi
================================================
FILE: db-charmer.gemspec
================================================
# -*- encoding: utf-8 -*-
$:.push File.expand_path('../lib', __FILE__)
require 'db_charmer/version'
Gem::Specification.new do |s|
s.name = 'db-charmer'
s.version = DbCharmer::Version::STRING
s.platform = Gem::Platform::RUBY
s.authors = [ 'Oleksiy Kovyrin' ]
s.email = 'alexey@kovyrin.net'
s.homepage = 'http://kovyrin.github.io/db-charmer/'
s.summary = 'ActiveRecord Connections Magic (slaves, multiple connections, etc)'
s.description = 'DbCharmer is a Rails plugin (and gem) that could be used to manage AR model connections, implement master/slave query schemes, sharding and other magic features many high-scale applications need.'
s.license = 'MIT'
s.rdoc_options = [ '--charset=UTF-8' ]
s.files = Dir['lib/**/*'] + Dir['*.rb']
s.files += %w[ README.rdoc LICENSE CHANGES ]
s.require_paths = [ 'lib' ]
s.extra_rdoc_files = [ 'LICENSE', 'README.rdoc' ]
# Dependencies
s.add_dependency 'activesupport', '< 4.0.0'
s.add_dependency 'activerecord', '< 4.0.0'
s.add_development_dependency 'rspec'
s.add_development_dependency 'yard'
s.add_development_dependency 'actionpack'
end
================================================
FILE: init.rb
================================================
require 'db_charmer'
================================================
FILE: issues/issues-as-of-2014-11-14.json
================================================
[
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/98",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/98/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/98/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/98/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/98",
"id": 45164122,
"number": 98,
"title": "Rails 4 blocker update_all may ignore condition with db_charmer !!",
"user": {
"login": "AvnerCohen",
"id": 1297254,
"avatar_url": "https://avatars.githubusercontent.com/u/1297254?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/AvnerCohen",
"html_url": "https://github.com/AvnerCohen",
"followers_url": "https://api.github.com/users/AvnerCohen/followers",
"following_url": "https://api.github.com/users/AvnerCohen/following{/other_user}",
"gists_url": "https://api.github.com/users/AvnerCohen/gists{/gist_id}",
"starred_url": "https://api.github.com/users/AvnerCohen/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/AvnerCohen/subscriptions",
"organizations_url": "https://api.github.com/users/AvnerCohen/orgs",
"repos_url": "https://api.github.com/users/AvnerCohen/repos",
"events_url": "https://api.github.com/users/AvnerCohen/events{/privacy}",
"received_events_url": "https://api.github.com/users/AvnerCohen/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2014-10-07T20:42:29Z",
"updated_at": "2014-10-07T20:42:29Z",
"closed_at": null,
"body": "First thing first, thanks for making this gem and putting the effort into it! :bow: \r\n...\r\n\r\nTo the issue, it might just be that this is a combination of an old code being upgraded from Rails 3 to Rails 4, But it is extremely dangerous.\r\n\r\nConsider the following console code:\r\n\r\n````ruby\r\n› rails c\r\nLoading development environment (Rails 4.1.6)\r\n2.1.2 :001 > Test.update_all({updated_at: Time.now}, {somevalue: 123})\r\nArgumentError: wrong number of arguments (2 for 1)\r\n from ./gems/activerecord-4.1.6/lib/active_record/relation.rb:316:in `update_all'\r\n from ./bundler/gems/db-charmer-cb40007c36e2/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:128:in `block in update_all_with_db_charmer'\r\n from ./bundler/gems/db-charmer-cb40007c36e2/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:103:in `block in switch_connection_for_method'\r\n from ./bundler/gems/db-charmer-cb40007c36e2/lib/db_charmer/active_record/multi_db_proxy.rb:37:in `on_db'\r\n from ./bundler/gems/db-charmer-cb40007c36e2/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:102:in `switch_connection_for_method'\r\n from ./bundler/gems/db-charmer-cb40007c36e2/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:127:in `update_all_with_db_charmer'\r\n from ./gems/activerecord-4.1.6/lib/active_record/querying.rb:8:in `update_all'\r\n from (irb):1\r\n from ./gems/railties-4.1.6/lib/rails/commands/console.rb:90:in `start'\r\n from ./gems/railties-4.1.6/lib/rails/commands/console.rb:9:in `start'\r\n from ./gems/railties-4.1.6/lib/rails/commands/commands_tasks.rb:69:in `console'\r\n from ./gems/railties-4.1.6/lib/rails/commands/commands_tasks.rb:40:in `run_command!'\r\n from ./gems/railties-4.1.6/lib/rails/commands.rb:17:in `<top (required)>'\r\n from bin/rails:8:in `require'\r\n from bin/rails:8:in `<main>'\r\n2.1.2 :002 > Test.update_all({updated_at: Time.now})\r\n SQL (0.5ms) UPDATE \"tests\" SET \"updated_at\" = '2014-10-07 20:34:07.694313'\r\n => 0\r\n2.1.2 :003 > Test.update_all({updated_at: Time.now}, {somevalue: 123})\r\n SQL (0.2ms) UPDATE \"tests\" SET \"updated_at\" = '2014-10-07 20:34:12.975116'\r\n => 0\r\n\r\n````\r\nGemfile is simply:\r\n\r\n`````ruby\r\nsource 'https://rubygems.org'\r\n\r\ngem 'rails', '4.1.6'\r\n\r\ngem 'sqlite3'\r\n\r\ngem 'db-charmer',\r\n :git => 'git@github.com:kovyrin/db-charmer.git',\r\n :branch => 'rails4', :ref => 'cb40007c36e2847850a37a490850cfd822016c5f', :require => 'db_charmer'\r\n````\r\n\r\n\r\n\r\nDescribing the issue:\r\n\r\n1. Calling update_all with wrong params (arity changed to 1 on rails 4) failes as expected.\r\n2. Enough to have a single update_all that passed succesfully.\r\n3. Next execution of wrong params (as [1] above) passes succesfully and arity check is ignored + conditions are totally ignored."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/97",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/97/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/97/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/97/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/97",
"id": 38187982,
"number": 97,
"title": "DB connections not closing properly",
"user": {
"login": "nchafai",
"id": 436617,
"avatar_url": "https://avatars.githubusercontent.com/u/436617?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/nchafai",
"html_url": "https://github.com/nchafai",
"followers_url": "https://api.github.com/users/nchafai/followers",
"following_url": "https://api.github.com/users/nchafai/following{/other_user}",
"gists_url": "https://api.github.com/users/nchafai/gists{/gist_id}",
"starred_url": "https://api.github.com/users/nchafai/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/nchafai/subscriptions",
"organizations_url": "https://api.github.com/users/nchafai/orgs",
"repos_url": "https://api.github.com/users/nchafai/repos",
"events_url": "https://api.github.com/users/nchafai/events{/privacy}",
"received_events_url": "https://api.github.com/users/nchafai/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 2,
"created_at": "2014-07-18T15:47:56Z",
"updated_at": "2014-07-21T07:17:26Z",
"closed_at": "2014-07-21T07:16:55Z",
"body": "Hi,\r\n\r\nWe are using db-charmer to handle distributed data accross multiple databases. However, connections are not closing properly when requests are made on a sharded database : hundreds of connections remain opened. \r\n\r\nAfter investigations, this situation is due to `abstract_connection_class_name` used to reference connections in `ConnectionPool` list : as long as different threads occur, a new connection is added in the pool list since `abstract_connection_class_name` is using the Thread id : \r\n```ruby\r\ndef self.abstract_connection_class_name(connection_name)\r\n conn_name_klass = connection_name.to_s.gsub(/\\W+/, '_').camelize\r\n thread = Thread.current.object_id.abs # need to make sure it is non-negative\r\n \"::AutoGeneratedAbstractConnectionClass#{conn_name_klass}ForThread#{thread}\"\r\nend\r\n```\r\n\r\nIf we just use ` \"::AutoGeneratedAbstractConnectionClass#{conn_name_klass}ForThread\"` without the `#{thread}` suffix part, everything looks fine, and connections are properly closed. \r\n\r\nSo, what is the exact purpose of having introduce this `#{thread}` suffix ? (this suffix is not present in the previous versions of db-charmer)"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/96",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/96/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/96/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/96/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/96",
"id": 35993889,
"number": 96,
"title": "[Rails 4] rake db:migrate:redo doesn't redo all migrations",
"user": {
"login": "akshetpandey",
"id": 1213060,
"avatar_url": "https://avatars.githubusercontent.com/u/1213060?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/akshetpandey",
"html_url": "https://github.com/akshetpandey",
"followers_url": "https://api.github.com/users/akshetpandey/followers",
"following_url": "https://api.github.com/users/akshetpandey/following{/other_user}",
"gists_url": "https://api.github.com/users/akshetpandey/gists{/gist_id}",
"starred_url": "https://api.github.com/users/akshetpandey/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/akshetpandey/subscriptions",
"organizations_url": "https://api.github.com/users/akshetpandey/orgs",
"repos_url": "https://api.github.com/users/akshetpandey/repos",
"events_url": "https://api.github.com/users/akshetpandey/events{/privacy}",
"received_events_url": "https://api.github.com/users/akshetpandey/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2014-06-18T14:58:18Z",
"updated_at": "2014-07-08T00:00:58Z",
"closed_at": "2014-07-08T00:00:58Z",
"body": "I am using the rails 4 branch with rails 4. The migrations work fine but when I try to redo the migrations, only the last two migrations are picked for redo."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/95",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/95/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/95/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/95/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/95",
"id": 35756037,
"number": 95,
"title": "Rails 4.1+",
"user": {
"login": "richpeck",
"id": 1104431,
"avatar_url": "https://avatars.githubusercontent.com/u/1104431?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/richpeck",
"html_url": "https://github.com/richpeck",
"followers_url": "https://api.github.com/users/richpeck/followers",
"following_url": "https://api.github.com/users/richpeck/following{/other_user}",
"gists_url": "https://api.github.com/users/richpeck/gists{/gist_id}",
"starred_url": "https://api.github.com/users/richpeck/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/richpeck/subscriptions",
"organizations_url": "https://api.github.com/users/richpeck/orgs",
"repos_url": "https://api.github.com/users/richpeck/repos",
"events_url": "https://api.github.com/users/richpeck/events{/privacy}",
"received_events_url": "https://api.github.com/users/richpeck/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 7,
"created_at": "2014-06-15T19:23:32Z",
"updated_at": "2014-11-03T15:25:13Z",
"closed_at": null,
"body": "Any chance we could get an updated ver to work with ActiveSupport 4.1+? \r\n\r\nIt's not compatible with the latest version of Rails otherwise :("
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/94",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/94/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/94/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/94/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/94",
"id": 28744882,
"number": 94,
"title": "Fix #93 Keep slave connections thread local.",
"user": {
"login": "gworley3",
"id": 809976,
"avatar_url": "https://avatars.githubusercontent.com/u/809976?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/gworley3",
"html_url": "https://github.com/gworley3",
"followers_url": "https://api.github.com/users/gworley3/followers",
"following_url": "https://api.github.com/users/gworley3/following{/other_user}",
"gists_url": "https://api.github.com/users/gworley3/gists{/gist_id}",
"starred_url": "https://api.github.com/users/gworley3/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/gworley3/subscriptions",
"organizations_url": "https://api.github.com/users/gworley3/orgs",
"repos_url": "https://api.github.com/users/gworley3/repos",
"events_url": "https://api.github.com/users/gworley3/events{/privacy}",
"received_events_url": "https://api.github.com/users/gworley3/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2014-03-04T21:57:32Z",
"updated_at": "2014-03-04T21:57:32Z",
"closed_at": null,
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/94",
"html_url": "https://github.com/kovyrin/db-charmer/pull/94",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/94.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/94.patch"
},
"body": "This is probably not an ideal fix for #93 but it seems to work."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/93",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/93/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/93/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/93/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/93",
"id": 28739552,
"number": 93,
"title": "Multi-threaded race conditions with Postgres",
"user": {
"login": "gworley3",
"id": 809976,
"avatar_url": "https://avatars.githubusercontent.com/u/809976?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/gworley3",
"html_url": "https://github.com/gworley3",
"followers_url": "https://api.github.com/users/gworley3/followers",
"following_url": "https://api.github.com/users/gworley3/following{/other_user}",
"gists_url": "https://api.github.com/users/gworley3/gists{/gist_id}",
"starred_url": "https://api.github.com/users/gworley3/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/gworley3/subscriptions",
"organizations_url": "https://api.github.com/users/gworley3/orgs",
"repos_url": "https://api.github.com/users/gworley3/repos",
"events_url": "https://api.github.com/users/gworley3/events{/privacy}",
"received_events_url": "https://api.github.com/users/gworley3/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2014-03-04T20:52:19Z",
"updated_at": "2014-07-09T00:38:31Z",
"closed_at": null,
"body": "Trying to use db-charmer 1.9.0 with Postgres and rails 3.2.17. Db-charmer works fine with this setup when single threaded. Running multiple threads via Sidekiq, I get the following error:\r\n\r\n```\r\n2014-03-04T20:28:37Z 40445 TID-ox250opo8 WARN: undefined method `fields' for nil:NilClass\r\n2014-03-04T20:28:37Z 40445 TID-ox250opo8 WARN: /Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/postgresql_adapter.rb:664:in `block in exec_query'\r\n```\r\n\r\nI believe I have traced this down to the way `PostgresqlAdapter` works in Rails. If you dig around in its code you'll find that it makes async calls to execute queries and expects no other query to execute on the same connection while the current query is executing. If another query comes along they end up in a race condition where one query gets a result (possibly the wrong one!) and the other gets nil.\r\n\r\nThis suggests db-charmer needs to do a better job of locking connections to particular threads so that a connection is not used by more than one thread at a time.\r\n\r\nFull stack trace for the curious:\r\n\r\n```\r\n2014-03-04T20:28:37Z 40445 TID-ox250opo8 WARN: {\"retry\"=>5, \"queue\"=>\"low_linkedin_metrics\", \"failures\"=>\"exhausted\", \"class\"=>\"MetricsWorker::Linkedin::ImportAdMetrics\", \"args\"=>[1, \"2013-02-09..2013-02-09\"], \"jid\"=>\"e968f2b5935d884385911a83\", \"enqueued_at\"=>1393960671.074003, \"error_message\"=>\"undefined method `fields' for nil:NilClass\", \"error_class\"=>\"NoMethodError\", \"failed_at\"=>1393964917.8832488, \"retry_count\"=>0}\r\n2014-03-04T20:28:37Z 40445 TID-ox250opo8 WARN: undefined method `fields' for nil:NilClass\r\n2014-03-04T20:28:37Z 40445 TID-ox250opo8 WARN: /Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/postgresql_adapter.rb:664:in `block in exec_query'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activesupport-3.2.17/lib/active_support/notifications/instrumenter.rb:20:in `instrument'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/abstract_adapter/connection_name.rb:14:in `instrument'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/instrumentation/active_record.rb:46:in `block in log_with_newrelic_instrumentation'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/method_tracer.rb:271:in `trace_execution_scoped'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/instrumentation/active_record.rb:43:in `log_with_newrelic_instrumentation'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/postgresql_adapter.rb:659:in `exec_query'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/postgresql_adapter.rb:1263:in `select'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/querying.rb:38:in `block in find_by_sql'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/explain.rb:41:in `logging_query_plan'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/querying.rb:37:in `find_by_sql'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/master_slave_routing.rb:13:in `block in find_by_sql'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:71:in `first_level_on_slave'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/master_slave_routing.rb:12:in `find_by_sql'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/method_tracer.rb:521:in `block in find_by_sql_with_trace_ActiveRecord_self_name_find_by_sql'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/method_tracer.rb:271:in `trace_execution_scoped'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/method_tracer.rb:516:in `find_by_sql_with_trace_ActiveRecord_self_name_find_by_sql'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation.rb:171:in `exec_queries'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation.rb:160:in `block in to_a'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/explain.rb:34:in `logging_query_plan'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation.rb:159:in `to_a'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:123:in `block in to_a_with_db_charmer'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:113:in `block in switch_connection_for_method'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:69:in `block in first_level_on_slave'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:40:in `on_db'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:59:in `on_slave'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:69:in `first_level_on_slave'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:112:in `switch_connection_for_method'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation/connection_routing.rb:122:in `to_a_with_db_charmer'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation/finder_methods.rb:381:in `find_first'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation/finder_methods.rb:122:in `first'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation/finder_methods.rb:267:in `find_by_attributes'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/dynamic_matchers.rb:50:in `method_missing'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation/delegation.rb:14:in `block in find_by_id'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation.rb:241:in `block in scoping'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/scoping.rb:98:in `with_scope'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation.rb:241:in `scoping'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/activerecord-3.2.17/lib/active_record/relation/delegation.rb:14:in `find_by_id'\r\n/Users/gworley3/github/adstage/adstage-platform-v2/app/workers/metrics_worker/linkedin/import_ad_metrics.rb:9:in `block in perform'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/db-charmer-1.9.0/lib/db_charmer/force_slave_reads.rb:50:in `force_slave_reads'\r\n/Users/gworley3/github/adstage/adstage-platform-v2/app/workers/metrics_worker/linkedin/import_ad_metrics.rb:8:in `perform'\r\n(eval):3:in `block in perform_with_newrelic_transaction_trace'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:318:in `perform_action_with_newrelic_trace'\r\n(eval):2:in `perform_with_newrelic_transaction_trace'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/processor.rb:49:in `block (3 levels) in process'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:122:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:122:in `block in invoke'\r\n/Users/gworley3/github/adstage/adstage-platform-v2/config/initializers/sidekiq.rb:9:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/instrumentation/sidekiq.rb:25:in `block in call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:318:in `perform_action_with_newrelic_trace'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/newrelic_rpm-3.6.4.122/lib/new_relic/agent/instrumentation/sidekiq.rb:21:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-unique-jobs-2.7.1/lib/sidekiq-unique-jobs/middleware/server/unique_jobs.rb:14:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-failures-0.3.0/lib/sidekiq/failures/middleware.rb:10:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-pro-1.4.3/lib/sidekiq/batch/middleware.rb:26:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/server/active_record.rb:6:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/server/retry_jobs.rb:62:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/server/logging.rb:11:in `block in call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/logging.rb:22:in `with_context'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/server/logging.rb:7:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:124:in `block in invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:127:in `call'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/middleware/chain.rb:127:in `invoke'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/processor.rb:48:in `block (2 levels) in process'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/processor.rb:105:in `stats'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/processor.rb:47:in `block in process'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/processor.rb:86:in `do_defer'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/sidekiq-2.17.6/lib/sidekiq/processor.rb:37:in `process'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/calls.rb:25:in `public_send'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/calls.rb:25:in `dispatch'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/calls.rb:122:in `dispatch'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/actor.rb:322:in `block in handle_message'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/actor.rb:416:in `block in task'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/tasks.rb:55:in `block in initialize'\r\n/Users/gworley3/.rvm/gems/ruby-2.0.0-p247@platform-v2/gems/celluloid-0.15.2/lib/celluloid/tasks/task_fiber.rb:13:in `block in create'\r\n```"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/92",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/92/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/92/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/92/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/92",
"id": 28669704,
"number": 92,
"title": "habtm associations support broken in rails 4 branch.",
"user": {
"login": "bobbarjung",
"id": 1243200,
"avatar_url": "https://avatars.githubusercontent.com/u/1243200?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/bobbarjung",
"html_url": "https://github.com/bobbarjung",
"followers_url": "https://api.github.com/users/bobbarjung/followers",
"following_url": "https://api.github.com/users/bobbarjung/following{/other_user}",
"gists_url": "https://api.github.com/users/bobbarjung/gists{/gist_id}",
"starred_url": "https://api.github.com/users/bobbarjung/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/bobbarjung/subscriptions",
"organizations_url": "https://api.github.com/users/bobbarjung/orgs",
"repos_url": "https://api.github.com/users/bobbarjung/repos",
"events_url": "https://api.github.com/users/bobbarjung/events{/privacy}",
"received_events_url": "https://api.github.com/users/bobbarjung/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 6,
"created_at": "2014-03-04T00:18:47Z",
"updated_at": "2014-07-29T14:40:22Z",
"closed_at": null,
"body": "Hi I have a connection to a recovery database and a habtm relationship between two models.\r\n\r\n```ruby\r\nclass Line\r\n has_and_belongs_to_many: nodes\r\nend\r\n\r\nclass Node\r\n has_and_belongs_to_many :lines\r\nend\r\n```\r\n\r\nI could access these relationships on the secondary database through db_charmer magic.\r\n\r\n```ruby\r\na = Node.on_db(:recovery).first\r\na.on_db(:recovery).lines.each {|b| < do stuff with b> }\r\n```\r\n\r\nBut with rails 4 branch of db_charmer gem (2.0.0.dev1)\r\n\r\nI simply get the following \r\n\r\n```\r\nirb(main):034:0> a.on_db(:recovery).lines\r\nirb(main):034:0># ActiveRecord::Associations::CollectionProxy []\r\n```\r\n\r\nAny interim way to get around this issue will also be appreciated."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/91",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/91/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/91/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/91/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/91",
"id": 28574942,
"number": 91,
"title": "can't query against the default db on_db(:default)",
"user": {
"login": "ohadpartuck",
"id": 2236337,
"avatar_url": "https://avatars.githubusercontent.com/u/2236337?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/ohadpartuck",
"html_url": "https://github.com/ohadpartuck",
"followers_url": "https://api.github.com/users/ohadpartuck/followers",
"following_url": "https://api.github.com/users/ohadpartuck/following{/other_user}",
"gists_url": "https://api.github.com/users/ohadpartuck/gists{/gist_id}",
"starred_url": "https://api.github.com/users/ohadpartuck/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ohadpartuck/subscriptions",
"organizations_url": "https://api.github.com/users/ohadpartuck/orgs",
"repos_url": "https://api.github.com/users/ohadpartuck/repos",
"events_url": "https://api.github.com/users/ohadpartuck/events{/privacy}",
"received_events_url": "https://api.github.com/users/ohadpartuck/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2014-03-02T07:33:20Z",
"updated_at": "2014-03-02T09:53:04Z",
"closed_at": "2014-03-02T09:52:28Z",
"body": "```ruby \r\ndevelopment: &development\r\n database: app_dev\r\n host: masterdb\r\n <<: *defaults\r\n\r\n slave:\r\n <<: *defaults\r\n host: slavedb01\r\n```\r\n\r\nthen trying to force a query against master\r\n``` MyModel.on_db(:default) ```\r\neven tried \r\n``` MyModel.on_master ```\r\n\r\nBut there is no specific querying against any db.\r\n"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/90",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/90/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/90/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/90/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/90",
"id": 28014934,
"number": 90,
"title": "RuntimeError: can't add a new key into hash during iteration",
"user": {
"login": "mhfs",
"id": 78422,
"avatar_url": "https://avatars.githubusercontent.com/u/78422?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/mhfs",
"html_url": "https://github.com/mhfs",
"followers_url": "https://api.github.com/users/mhfs/followers",
"following_url": "https://api.github.com/users/mhfs/following{/other_user}",
"gists_url": "https://api.github.com/users/mhfs/gists{/gist_id}",
"starred_url": "https://api.github.com/users/mhfs/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/mhfs/subscriptions",
"organizations_url": "https://api.github.com/users/mhfs/orgs",
"repos_url": "https://api.github.com/users/mhfs/repos",
"events_url": "https://api.github.com/users/mhfs/events{/privacy}",
"received_events_url": "https://api.github.com/users/mhfs/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 12,
"created_at": "2014-02-21T02:38:17Z",
"updated_at": "2014-06-03T23:26:05Z",
"closed_at": null,
"body": "Hey @kovyrin ,\r\n\r\nI think I might have found a multi-threading bug. Throwing it here to see it rings any bells.\r\n\r\nI'm processing a high volume of quick sidekiq jobs and part of it is performing a query like this:\r\n\r\n```ruby\r\nUser.on_db(:bbdb).find(user_id)\r\n```\r\n\r\nIm' seeing lot's of errors like this:\r\n\r\n```\r\nRuntimeError: can't add a new key into hash during iteration\r\n```\r\nI'm using ruby 2.0.0p353, rails 3.217 and db-charmer 1.9.0 as you can see in the full backtrace below.\r\n\r\nDoes that rings any bells for you?\r\n\r\nThanks in advance.\r\n\r\n```\r\n/vendor/ruby/2.0.0/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract/connection_pool.rb:375 in \"[]=\"\r\n/vendor/ruby/2.0.0/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract/connection_pool.rb:375 in \"establish_connection\"\r\n/vendor/ruby/2.0.0/gems/activerecord-3.2.17/lib/active_record/connection_adapters/abstract/connection_specification.rb:137 in \"establish_connection\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/active_record/connection_switching.rb:25 in \"establish_real_connection_if_exists\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/connection_factory.rb:51 in \"generate_abstract_class\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/connection_factory.rb:35 in \"establish_connection\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/connection_factory.rb:24 in \"connect\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/active_record/connection_switching.rb:66 in \"coerce_to_connection_proxy\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/active_record/connection_switching.rb:82 in \"switch_connection_to\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:39 in \"on_db\"\r\n/vendor/ruby/2.0.0/gems/db-charmer-1.9.0/lib/db_charmer/active_record/multi_db_proxy.rb:19 in \"method_missing\"\r\n/app/jobs/backfill_stats_job.rb:7 in \"perform\"\r\n```"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/89",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/89/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/89/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/89/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/89",
"id": 27979122,
"number": 89,
"title": "force_slave_reads option ignored",
"user": {
"login": "gworley3",
"id": 809976,
"avatar_url": "https://avatars.githubusercontent.com/u/809976?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/gworley3",
"html_url": "https://github.com/gworley3",
"followers_url": "https://api.github.com/users/gworley3/followers",
"following_url": "https://api.github.com/users/gworley3/following{/other_user}",
"gists_url": "https://api.github.com/users/gworley3/gists{/gist_id}",
"starred_url": "https://api.github.com/users/gworley3/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/gworley3/subscriptions",
"organizations_url": "https://api.github.com/users/gworley3/orgs",
"repos_url": "https://api.github.com/users/gworley3/repos",
"events_url": "https://api.github.com/users/gworley3/events{/privacy}",
"received_events_url": "https://api.github.com/users/gworley3/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2014-02-20T17:19:06Z",
"updated_at": "2014-02-20T17:41:46Z",
"closed_at": "2014-02-20T17:41:46Z",
"body": "I set `:force_slave_reads => false` in the `db_magic` opts but still reads from slaves by default."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/88",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/88/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/88/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/88/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/88",
"id": 24576212,
"number": 88,
"title": "Skip HasAndBelongsToMany preloader for Rails 4.1",
"user": {
"login": "kmcbride",
"id": 597435,
"avatar_url": "https://avatars.githubusercontent.com/u/597435?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/kmcbride",
"html_url": "https://github.com/kmcbride",
"followers_url": "https://api.github.com/users/kmcbride/followers",
"following_url": "https://api.github.com/users/kmcbride/following{/other_user}",
"gists_url": "https://api.github.com/users/kmcbride/gists{/gist_id}",
"starred_url": "https://api.github.com/users/kmcbride/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/kmcbride/subscriptions",
"organizations_url": "https://api.github.com/users/kmcbride/orgs",
"repos_url": "https://api.github.com/users/kmcbride/repos",
"events_url": "https://api.github.com/users/kmcbride/events{/privacy}",
"received_events_url": "https://api.github.com/users/kmcbride/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2013-12-19T18:31:26Z",
"updated_at": "2014-06-11T19:21:31Z",
"closed_at": "2014-06-11T19:21:31Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/88",
"html_url": "https://github.com/kovyrin/db-charmer/pull/88",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/88.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/88.patch"
},
"body": "See: https://github.com/rails/rails/commit/a03ea3ff97b43340d0904525083bf8bc7a1c6ebc"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/87",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/87/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/87/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/87/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/87",
"id": 24129460,
"number": 87,
"title": "Make database rake auto load on rails",
"user": {
"login": "arthurnn",
"id": 833383,
"avatar_url": "https://avatars.githubusercontent.com/u/833383?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/arthurnn",
"html_url": "https://github.com/arthurnn",
"followers_url": "https://api.github.com/users/arthurnn/followers",
"following_url": "https://api.github.com/users/arthurnn/following{/other_user}",
"gists_url": "https://api.github.com/users/arthurnn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/arthurnn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/arthurnn/subscriptions",
"organizations_url": "https://api.github.com/users/arthurnn/orgs",
"repos_url": "https://api.github.com/users/arthurnn/repos",
"events_url": "https://api.github.com/users/arthurnn/events{/privacy}",
"received_events_url": "https://api.github.com/users/arthurnn/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 3,
"created_at": "2013-12-11T19:02:34Z",
"updated_at": "2013-12-12T23:09:55Z",
"closed_at": "2013-12-12T23:08:46Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/87",
"html_url": "https://github.com/kovyrin/db-charmer/pull/87",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/87.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/87.patch"
},
"body": "@kovyrin \r\n\r\nWe need to load the rake task on `Rails::Railtie`, otherwise they wont be available when just adding the Gem.\r\n\r\nlet me know what you think.\r\n\r\ncheers,"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/86",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/86/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/86/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/86/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/86",
"id": 23877630,
"number": 86,
"title": "Allow AR::B.db_magic m/s split to work with abstract AR classes.",
"user": {
"login": "perplexes",
"id": 13812,
"avatar_url": "https://avatars.githubusercontent.com/u/13812?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/perplexes",
"html_url": "https://github.com/perplexes",
"followers_url": "https://api.github.com/users/perplexes/followers",
"following_url": "https://api.github.com/users/perplexes/following{/other_user}",
"gists_url": "https://api.github.com/users/perplexes/gists{/gist_id}",
"starred_url": "https://api.github.com/users/perplexes/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/perplexes/subscriptions",
"organizations_url": "https://api.github.com/users/perplexes/orgs",
"repos_url": "https://api.github.com/users/perplexes/repos",
"events_url": "https://api.github.com/users/perplexes/events{/privacy}",
"received_events_url": "https://api.github.com/users/perplexes/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2013-12-06T18:56:28Z",
"updated_at": "2013-12-06T18:56:28Z",
"closed_at": null,
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/86",
"html_url": "https://github.com/kovyrin/db-charmer/pull/86",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/86.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/86.patch"
},
"body": "Hi, ran into a SystemStackError. We wanted to split all reads in all models to slaves. The easiest way to do this seemed like:\r\n\r\nIn config/initializers/db_charmer.rb:\r\n```ruby\r\nActiveRecord::Base.db_magic(slave: :main_slave)\r\n```\r\n\r\nBut we also have Rails Engines that have their own version of an AR::B-like class with a separate connection, called base:\r\n\r\n```ruby\r\nclass IsbnDb::Base < ActiveRecord::Base\r\n self.abstract_class = true\r\n db_magic connection: :isbn_master, slave: :isbn_slave\r\nend\r\n```\r\n\r\nThen models underneath that would inherit this connection:\r\n```ruby\r\nclass Isbn < IsbnDb::Base\r\nend\r\n```\r\n\r\nWhat we were seeing were SystemStackErrors:\r\n\r\n```ruby\r\n[3] pry(main)> Isbn.first\r\nSystemStackError: stack level too deep\r\n```\r\n\r\nAfter a lot of tracing (and set_trace_func), the culprit is that putting db_magic on ActiveRecord::Base overrides the default behavior of the master/slave automatic methods like reload, find_by_sql and count_by_sql. In models that directly inherit from AR::B (like User, say) this behavior is fine - but in level-2 inherited models (AR::B > Base > Isbn), is causes infinite recursion.\r\n\r\nThis pull request fixes this situation, but I don't quite know how to test it."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/85",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/85/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/85/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/85/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/85",
"id": 22639819,
"number": 85,
"title": "Rails4 Support",
"user": {
"login": "kovyrin",
"id": 3467,
"avatar_url": "https://avatars.githubusercontent.com/u/3467?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/kovyrin",
"html_url": "https://github.com/kovyrin",
"followers_url": "https://api.github.com/users/kovyrin/followers",
"following_url": "https://api.github.com/users/kovyrin/following{/other_user}",
"gists_url": "https://api.github.com/users/kovyrin/gists{/gist_id}",
"starred_url": "https://api.github.com/users/kovyrin/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/kovyrin/subscriptions",
"organizations_url": "https://api.github.com/users/kovyrin/orgs",
"repos_url": "https://api.github.com/users/kovyrin/repos",
"events_url": "https://api.github.com/users/kovyrin/events{/privacy}",
"received_events_url": "https://api.github.com/users/kovyrin/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 16,
"created_at": "2013-11-14T02:58:39Z",
"updated_at": "2014-10-22T09:35:58Z",
"closed_at": null,
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/85",
"html_url": "https://github.com/kovyrin/db-charmer/pull/85",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/85.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/85.patch"
},
"body": "This PR is used to track the process of adding Rails 4 support to DbCharmer. It is not ready yet, but we are really close."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/84",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/84/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/84/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/84/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/84",
"id": 22639397,
"number": 84,
"title": "License missing from gemspec",
"user": {
"login": "bf4",
"id": 142914,
"avatar_url": "https://avatars.githubusercontent.com/u/142914?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/bf4",
"html_url": "https://github.com/bf4",
"followers_url": "https://api.github.com/users/bf4/followers",
"following_url": "https://api.github.com/users/bf4/following{/other_user}",
"gists_url": "https://api.github.com/users/bf4/gists{/gist_id}",
"starred_url": "https://api.github.com/users/bf4/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/bf4/subscriptions",
"organizations_url": "https://api.github.com/users/bf4/orgs",
"repos_url": "https://api.github.com/users/bf4/repos",
"events_url": "https://api.github.com/users/bf4/events{/privacy}",
"received_events_url": "https://api.github.com/users/bf4/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 2,
"created_at": "2013-11-14T02:46:06Z",
"updated_at": "2013-11-14T04:18:04Z",
"closed_at": "2013-11-14T02:57:03Z",
"body": " RubyGems.org doesn't report a license for your gem. This is because it is not specified in the [gemspec](http://docs.rubygems.org/read/chapter/20#license) of your last release.\n\n via e.g.\n\n spec.license = 'MIT'\n # or\n spec.licenses = ['MIT', 'GPL-2']\n\n Including a license in your gemspec is an easy way for rubygems.org and other tools to check how your gem is licensed. As you can imagine, scanning your repository for a LICENSE file or parsing the README, and then attempting to identify the license or licenses is much more difficult and more error prone. So, even for projects that already specify a license, including a license in your gemspec is a good practice. See, for example, how [rubygems.org uses the gemspec to display the rails gem license](https://rubygems.org/gems/rails).\n\n There is even a [License Finder gem](https://github.com/pivotal/LicenseFinder) to help companies/individuals ensure all gems they use meet their licensing needs. This tool depends on license information being available in the gemspec. This is an important enough issue that *even Bundler now generates gems with a default 'MIT' license*.\n\n I hope you'll consider specifying a license in your gemspec. If not, please just close the issue with a nice message. In either case, I'll follow up. Thanks for your time!\n\n Appendix:\n\n If you need help choosing a [license](http://opensource.org/licenses) (sorry, I haven't checked your readme or looked for a license file), GitHub has created a [license picker tool](http://choosealicense.com/). Code without a license specified defaults to 'All rights reserved'-- denying others all rights to use of the code.\n Here's a [list of the license names I've found and their frequencies](https://github.com/bf4/gemproject/blob/master/license_usage.csv)\n\n p.s. In case you're wondering how I found you and why I made this issue, it's because I'm collecting stats on gems (I was originally looking for download data) and decided to collect license metadata,too, and [make issues for gemspecs not specifying a license as a public service :)](https://github.com/bf4/gemproject/issues/1). See the previous link or my [blog post about this project for more information](http://www.benjaminfleischer.com/2013/07/12/make-the-world-a-better-place-put-a-license-in-your-gemspec/).\n"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/83",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/83/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/83/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/83/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/83",
"id": 22158156,
"number": 83,
"title": "Gemspec updates",
"user": {
"login": "bradherman",
"id": 384172,
"avatar_url": "https://avatars.githubusercontent.com/u/384172?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/bradherman",
"html_url": "https://github.com/bradherman",
"followers_url": "https://api.github.com/users/bradherman/followers",
"following_url": "https://api.github.com/users/bradherman/following{/other_user}",
"gists_url": "https://api.github.com/users/bradherman/gists{/gist_id}",
"starred_url": "https://api.github.com/users/bradherman/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/bradherman/subscriptions",
"organizations_url": "https://api.github.com/users/bradherman/orgs",
"repos_url": "https://api.github.com/users/bradherman/repos",
"events_url": "https://api.github.com/users/bradherman/events{/privacy}",
"received_events_url": "https://api.github.com/users/bradherman/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-11-05T22:50:37Z",
"updated_at": "2013-11-10T06:31:59Z",
"closed_at": "2013-11-10T06:31:59Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/83",
"html_url": "https://github.com/kovyrin/db-charmer/pull/83",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/83.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/83.patch"
},
"body": ""
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/82",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/82/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/82/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/82/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/82",
"id": 22002182,
"number": 82,
"title": "Update db-charmer.gemspec",
"user": {
"login": "yhuang",
"id": 154587,
"avatar_url": "https://avatars.githubusercontent.com/u/154587?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/yhuang",
"html_url": "https://github.com/yhuang",
"followers_url": "https://api.github.com/users/yhuang/followers",
"following_url": "https://api.github.com/users/yhuang/following{/other_user}",
"gists_url": "https://api.github.com/users/yhuang/gists{/gist_id}",
"starred_url": "https://api.github.com/users/yhuang/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/yhuang/subscriptions",
"organizations_url": "https://api.github.com/users/yhuang/orgs",
"repos_url": "https://api.github.com/users/yhuang/repos",
"events_url": "https://api.github.com/users/yhuang/events{/privacy}",
"received_events_url": "https://api.github.com/users/yhuang/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-11-02T14:09:36Z",
"updated_at": "2013-11-10T15:41:32Z",
"closed_at": "2013-11-10T15:41:32Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/82",
"html_url": "https://github.com/kovyrin/db-charmer/pull/82",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/82.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/82.patch"
},
"body": "Rails 4.0.1 has been released:\r\n\r\nhttp://weblog.rubyonrails.org/2013/11/1/Rails-4-0-1-has-been-released/"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/81",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/81/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/81/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/81/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/81",
"id": 21460804,
"number": 81,
"title": "Sharded connection key parameter meaning?",
"user": {
"login": "fabn",
"id": 324213,
"avatar_url": "https://avatars.githubusercontent.com/u/324213?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/fabn",
"html_url": "https://github.com/fabn",
"followers_url": "https://api.github.com/users/fabn/followers",
"following_url": "https://api.github.com/users/fabn/following{/other_user}",
"gists_url": "https://api.github.com/users/fabn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/fabn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/fabn/subscriptions",
"organizations_url": "https://api.github.com/users/fabn/orgs",
"repos_url": "https://api.github.com/users/fabn/repos",
"events_url": "https://api.github.com/users/fabn/events{/privacy}",
"received_events_url": "https://api.github.com/users/fabn/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2013-10-23T15:14:48Z",
"updated_at": "2013-10-23T15:14:48Z",
"closed_at": null,
"body": "In the readme there is this example for sharded connections\r\n\r\n```ruby\r\nclass Text < ActiveRecord::Base\r\n db_magic :sharded => {\r\n :key => :id,\r\n :sharded_connection => :texts\r\n }\r\nend\r\n```\r\n\r\nWhat is the meaning of `:key` parameter? I saw that it's not used at all in [setup_sharding_magic](https://github.com/kovyrin/db-charmer/blob/master/lib/db_charmer/active_record/db_magic.rb#L53) method\r\n\r\nI assumed that the usage of that field is to compute the shard before saving or when retrieving records, something like \r\n\r\n```ruby\r\nSHARDING_MAP = {\r\n 'US' => :us_users,\r\n 'CA' => :ca_users,\r\n :default => :other_users\r\n}\r\n\r\nDbCharmer::Sharding.register_connection(\r\n :name => :users,\r\n :method => :hash_map,\r\n :map => SHARDING_MAP\r\n)\r\n\r\nclass User < ActiveRecord::Base\r\n db_magic :sharded => {\r\n :key => :locale,\r\n :sharded_connection => :users\r\n }\r\nend\r\n```\r\n\r\nAnd then when creating users\r\n\r\n```ruby\r\nUser.new(locale: 'US').save # this goes to us_users shard\r\nUser.new(locale: 'CA').save # this goes to ca_users shard\r\n```\r\n\r\nBut this kind of code is not working at all, shard must be selected manually before any operation. Am I right? \r\n\r\nIn that case what is the meaning of sharding? The same effect can (almost) be achieved with normal `on_db` method calls?"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/80",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/80/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/80/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/80/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/80",
"id": 21106472,
"number": 80,
"title": "Bump rails to 3.2.15",
"user": {
"login": "arthurnn",
"id": 833383,
"avatar_url": "https://avatars.githubusercontent.com/u/833383?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/arthurnn",
"html_url": "https://github.com/arthurnn",
"followers_url": "https://api.github.com/users/arthurnn/followers",
"following_url": "https://api.github.com/users/arthurnn/following{/other_user}",
"gists_url": "https://api.github.com/users/arthurnn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/arthurnn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/arthurnn/subscriptions",
"organizations_url": "https://api.github.com/users/arthurnn/orgs",
"repos_url": "https://api.github.com/users/arthurnn/repos",
"events_url": "https://api.github.com/users/arthurnn/events{/privacy}",
"received_events_url": "https://api.github.com/users/arthurnn/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2013-10-16T20:13:02Z",
"updated_at": "2013-10-16T20:13:33Z",
"closed_at": "2013-10-16T20:13:33Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/80",
"html_url": "https://github.com/kovyrin/db-charmer/pull/80",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/80.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/80.patch"
},
"body": ""
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/79",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/79/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/79/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/79/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/79",
"id": 19604764,
"number": 79,
"title": "Connection not switching connection consistantly.",
"user": {
"login": "tysliu",
"id": 68217,
"avatar_url": "https://avatars.githubusercontent.com/u/68217?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/tysliu",
"html_url": "https://github.com/tysliu",
"followers_url": "https://api.github.com/users/tysliu/followers",
"following_url": "https://api.github.com/users/tysliu/following{/other_user}",
"gists_url": "https://api.github.com/users/tysliu/gists{/gist_id}",
"starred_url": "https://api.github.com/users/tysliu/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/tysliu/subscriptions",
"organizations_url": "https://api.github.com/users/tysliu/orgs",
"repos_url": "https://api.github.com/users/tysliu/repos",
"events_url": "https://api.github.com/users/tysliu/events{/privacy}",
"received_events_url": "https://api.github.com/users/tysliu/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 6,
"created_at": "2013-09-17T09:49:32Z",
"updated_at": "2013-11-14T03:45:53Z",
"closed_at": null,
"body": "Hi,\r\nI'm eager loading an association for a model. for example Model.where('criteria').includes(:some_association)\r\n\r\nThis association is from another database, I'm finding that if the query for Model.where('criteria') takes too long. our view will throw an error telling us ActionView::Template::Error (Mysql2::Error: Table 'database.some_association' doesn't exist.\r\n\r\nIt would be most appreciated if someone can shed some light on this issue!"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/78",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/78/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/78/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/78/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/78",
"id": 19461002,
"number": 78,
"title": "Kill rails 2 support",
"user": {
"login": "arthurnn",
"id": 833383,
"avatar_url": "https://avatars.githubusercontent.com/u/833383?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/arthurnn",
"html_url": "https://github.com/arthurnn",
"followers_url": "https://api.github.com/users/arthurnn/followers",
"following_url": "https://api.github.com/users/arthurnn/following{/other_user}",
"gists_url": "https://api.github.com/users/arthurnn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/arthurnn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/arthurnn/subscriptions",
"organizations_url": "https://api.github.com/users/arthurnn/orgs",
"repos_url": "https://api.github.com/users/arthurnn/repos",
"events_url": "https://api.github.com/users/arthurnn/events{/privacy}",
"received_events_url": "https://api.github.com/users/arthurnn/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-09-13T15:59:17Z",
"updated_at": "2013-11-10T15:44:43Z",
"closed_at": "2013-11-10T15:44:43Z",
"body": "If @kovyrin is ok with this idea, I can submit a PR to cleaning up code that is there only because of rails 2.\r\nThoughts on that?"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/77",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/77/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/77/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/77/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/77",
"id": 19411140,
"number": 77,
"title": "Rescue error on drop database on the main db",
"user": {
"login": "arthurnn",
"id": 833383,
"avatar_url": "https://avatars.githubusercontent.com/u/833383?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/arthurnn",
"html_url": "https://github.com/arthurnn",
"followers_url": "https://api.github.com/users/arthurnn/followers",
"following_url": "https://api.github.com/users/arthurnn/following{/other_user}",
"gists_url": "https://api.github.com/users/arthurnn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/arthurnn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/arthurnn/subscriptions",
"organizations_url": "https://api.github.com/users/arthurnn/orgs",
"repos_url": "https://api.github.com/users/arthurnn/repos",
"events_url": "https://api.github.com/users/arthurnn/events{/privacy}",
"received_events_url": "https://api.github.com/users/arthurnn/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-09-12T20:02:28Z",
"updated_at": "2013-10-16T20:08:52Z",
"closed_at": "2013-10-16T20:08:52Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/77",
"html_url": "https://github.com/kovyrin/db-charmer/pull/77",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/77.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/77.patch"
},
"body": "we have this type of config:\r\n\r\n```ruby\r\ndevelopment: &development\r\n database: foo\r\n\r\nbenchmark: &benchmark\r\n database: foo\r\n```\r\n\r\nwhen dropping all it throws an exception as foo was dropped already. "
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/76",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/76/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/76/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/76/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/76",
"id": 19410987,
"number": 76,
"title": "Update .travis.yml",
"user": {
"login": "arthurnn",
"id": 833383,
"avatar_url": "https://avatars.githubusercontent.com/u/833383?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/arthurnn",
"html_url": "https://github.com/arthurnn",
"followers_url": "https://api.github.com/users/arthurnn/followers",
"following_url": "https://api.github.com/users/arthurnn/following{/other_user}",
"gists_url": "https://api.github.com/users/arthurnn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/arthurnn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/arthurnn/subscriptions",
"organizations_url": "https://api.github.com/users/arthurnn/orgs",
"repos_url": "https://api.github.com/users/arthurnn/repos",
"events_url": "https://api.github.com/users/arthurnn/events{/privacy}",
"received_events_url": "https://api.github.com/users/arthurnn/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2013-09-12T19:59:31Z",
"updated_at": "2013-09-12T20:23:12Z",
"closed_at": "2013-09-12T20:22:48Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/76",
"html_url": "https://github.com/kovyrin/db-charmer/pull/76",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/76.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/76.patch"
},
"body": "use RAILS_VERSION=3.2.14 on travis."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/75",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/75/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/75/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/75/events",
"html_url": "https://github.com/kovyrin/db-charmer/pull/75",
"id": 19130612,
"number": 75,
"title": "Update rails version limits to 3.2.14",
"user": {
"login": "beedub",
"id": 102646,
"avatar_url": "https://avatars.githubusercontent.com/u/102646?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/beedub",
"html_url": "https://github.com/beedub",
"followers_url": "https://api.github.com/users/beedub/followers",
"following_url": "https://api.github.com/users/beedub/following{/other_user}",
"gists_url": "https://api.github.com/users/beedub/gists{/gist_id}",
"starred_url": "https://api.github.com/users/beedub/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/beedub/subscriptions",
"organizations_url": "https://api.github.com/users/beedub/orgs",
"repos_url": "https://api.github.com/users/beedub/repos",
"events_url": "https://api.github.com/users/beedub/events{/privacy}",
"received_events_url": "https://api.github.com/users/beedub/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-09-06T21:56:18Z",
"updated_at": "2013-09-06T21:58:53Z",
"closed_at": "2013-09-06T21:58:48Z",
"pull_request": {
"url": "https://api.github.com/repos/kovyrin/db-charmer/pulls/75",
"html_url": "https://github.com/kovyrin/db-charmer/pull/75",
"diff_url": "https://github.com/kovyrin/db-charmer/pull/75.diff",
"patch_url": "https://github.com/kovyrin/db-charmer/pull/75.patch"
},
"body": ""
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/74",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/74/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/74/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/74/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/74",
"id": 16779471,
"number": 74,
"title": "hasone relationship does not seem to work with db-charmer",
"user": {
"login": "bobbarjung",
"id": 1243200,
"avatar_url": "https://avatars.githubusercontent.com/u/1243200?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/bobbarjung",
"html_url": "https://github.com/bobbarjung",
"followers_url": "https://api.github.com/users/bobbarjung/followers",
"following_url": "https://api.github.com/users/bobbarjung/following{/other_user}",
"gists_url": "https://api.github.com/users/bobbarjung/gists{/gist_id}",
"starred_url": "https://api.github.com/users/bobbarjung/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/bobbarjung/subscriptions",
"organizations_url": "https://api.github.com/users/bobbarjung/orgs",
"repos_url": "https://api.github.com/users/bobbarjung/repos",
"events_url": "https://api.github.com/users/bobbarjung/events{/privacy}",
"received_events_url": "https://api.github.com/users/bobbarjung/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 0,
"created_at": "2013-07-15T21:16:41Z",
"updated_at": "2014-06-11T21:06:07Z",
"closed_at": null,
"body": "I have a has_one relationship between A and B\r\n\r\n```ruby\r\nclass A < ActiveRecord::Base\r\n has_one b\r\nend\r\n\r\nclass B < ActiveRecord::Base\r\n belongs_to a\r\nend\r\n```\r\n\r\nI want to access the associations on a secondary db. (Called recovery) using db-charmer.\r\n\r\n```ruby\r\nb = B.on_db(:recovery).find(b_id) # works\r\nb.on_db(:recovery).a # works. a is not nil.\r\n\r\na = A.on_db(:recovery).find(a_id) # works.\r\na.on_db(:recovery).b # does not work,\r\n```\r\n...as it tries to lookup the main db and not the recovery database for the reverse lookup. I am guessing has_many also will not work? I am using db-charmer version 1.8.4.\r\n\r\nThank you for your help."
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/73",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/73/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/73/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/73/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/73",
"id": 16121766,
"number": 73,
"title": "Multi-Threading: with_remapped_databases fails to remap classes",
"user": {
"login": "chadrem",
"id": 22150,
"avatar_url": "https://avatars.githubusercontent.com/u/22150?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/chadrem",
"html_url": "https://github.com/chadrem",
"followers_url": "https://api.github.com/users/chadrem/followers",
"following_url": "https://api.github.com/users/chadrem/following{/other_user}",
"gists_url": "https://api.github.com/users/chadrem/gists{/gist_id}",
"starred_url": "https://api.github.com/users/chadrem/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/chadrem/subscriptions",
"organizations_url": "https://api.github.com/users/chadrem/orgs",
"repos_url": "https://api.github.com/users/chadrem/repos",
"events_url": "https://api.github.com/users/chadrem/events{/privacy}",
"received_events_url": "https://api.github.com/users/chadrem/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/labels/reproducible-issue",
"name": "reproducible-issue",
"color": "e10c02"
}
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 4,
"created_at": "2013-06-28T00:27:00Z",
"updated_at": "2014-06-11T21:01:35Z",
"closed_at": "2014-06-11T21:01:35Z",
"body": "I started digging into the problem and noticed that new threads are unable to find the map. Because of this, no classes get re-mapped and thus look for data in the wrong database.\r\n\r\n#### Main thread works correctly (it finds the map).\r\n>> puts ::ActiveRecord::Base.db_charmer_database_remappings.inspect\r\n{:limbo=>:realm_0}\r\n\r\n#### New threads don't work (unable to find the above map).\r\n>> Thread.new { puts ::ActiveRecord::Base.db_charmer_database_remappings.inspect }\r\n{}"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/72",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/72/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/72/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/72/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/72",
"id": 15789793,
"number": 72,
"title": "Difference in schemas between master and slave affects whole app.",
"user": {
"login": "andriytyurnikov",
"id": 3668,
"avatar_url": "https://avatars.githubusercontent.com/u/3668?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/andriytyurnikov",
"html_url": "https://github.com/andriytyurnikov",
"followers_url": "https://api.github.com/users/andriytyurnikov/followers",
"following_url": "https://api.github.com/users/andriytyurnikov/following{/other_user}",
"gists_url": "https://api.github.com/users/andriytyurnikov/gists{/gist_id}",
"starred_url": "https://api.github.com/users/andriytyurnikov/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/andriytyurnikov/subscriptions",
"organizations_url": "https://api.github.com/users/andriytyurnikov/orgs",
"repos_url": "https://api.github.com/users/andriytyurnikov/repos",
"events_url": "https://api.github.com/users/andriytyurnikov/events{/privacy}",
"received_events_url": "https://api.github.com/users/andriytyurnikov/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-06-20T09:39:08Z",
"updated_at": "2013-11-10T15:49:36Z",
"closed_at": "2013-11-10T15:49:36Z",
"body": "We had long-running migration on db master (lhm gem), and as one might expect there was some delay between master and slave.\r\nSo when migration finished on master, but was in progress on slave - we had different schemas.\r\nUnexpected surprise is that this difference affected parts of the app which do not use slave connection.\r\n\r\nMysql2::Error: Unknown column 'referrer' in 'field list': INSERT INTO `purchases` (`coupon_code`, `created_at`, `customer_id`, `dont_redeem`, `email`, `encrypted_email`, `ip_address`, `order_date`, `order_number`, `referrer`, `site_id`, `subtotal`, `updated_at`, `visitor_id`) VALUES ('CODE42', '2013-06-19 12:19:51', NULL, 0, 'email@gmail.com', NULL, '127.0.0.1', '2013-06-19 12:19:51', '100379070', NULL, 1887, 123.2, '2013-06-19 12:19:51', 26179393)\r\n\r\nAt the moment of the exception raise referrer column was present on master, but was not present on slave. Unexpected surprise here, is that controller, which raised this exception does not use db-charmer slave. Somehow db-charmer slave connection affects operations on master connection (schema info cached somewhere by activerecord?)"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/71",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/71/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/71/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/71/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/71",
"id": 15777336,
"number": 71,
"title": "Forcing writes to master in bang methods (create!, etc)",
"user": {
"login": "kpumuk",
"id": 10163,
"avatar_url": "https://avatars.githubusercontent.com/u/10163?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/kpumuk",
"html_url": "https://github.com/kpumuk",
"followers_url": "https://api.github.com/users/kpumuk/followers",
"following_url": "https://api.github.com/users/kpumuk/following{/other_user}",
"gists_url": "https://api.github.com/users/kpumuk/gists{/gist_id}",
"starred_url": "https://api.github.com/users/kpumuk/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/kpumuk/subscriptions",
"organizations_url": "https://api.github.com/users/kpumuk/orgs",
"repos_url": "https://api.github.com/users/kpumuk/repos",
"events_url": "https://api.github.com/users/kpumuk/events{/privacy}",
"received_events_url": "https://api.github.com/users/kpumuk/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/labels/reproducible-issue",
"name": "reproducible-issue",
"color": "e10c02"
}
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 1,
"created_at": "2013-06-20T01:27:59Z",
"updated_at": "2013-06-20T01:31:16Z",
"closed_at": null,
"body": "Currently db-charmer forces writes to master for `create`, `update`, `delete`, and some other ActiveRecord methods. Unfortunately, `create!` does not get forced to use master:\r\n\r\n ree-1.8.7-2012.02 >> TestModel.on_db(:slave).create\r\n SQL (0.2ms) BEGIN\r\n \r\n ree-1.8.7-2012.02 >> TestModel.on_db(:slave).create!\r\n [slave] SQL (0.1ms) BEGIN\r\n\r\nIt seems like problematic code is in `master_slave_routing.rb` for Rails 2.x"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/70",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/70/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/70/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/70/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/70",
"id": 15004735,
"number": 70,
"title": "Support for sharing a connection to same server / switching databases as necessary",
"user": {
"login": "boourns",
"id": 699550,
"avatar_url": "https://avatars.githubusercontent.com/u/699550?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/boourns",
"html_url": "https://github.com/boourns",
"followers_url": "https://api.github.com/users/boourns/followers",
"following_url": "https://api.github.com/users/boourns/following{/other_user}",
"gists_url": "https://api.github.com/users/boourns/gists{/gist_id}",
"starred_url": "https://api.github.com/users/boourns/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/boourns/subscriptions",
"organizations_url": "https://api.github.com/users/boourns/orgs",
"repos_url": "https://api.github.com/users/boourns/repos",
"events_url": "https://api.github.com/users/boourns/events{/privacy}",
"received_events_url": "https://api.github.com/users/boourns/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "open",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 2,
"created_at": "2013-05-31T17:41:34Z",
"updated_at": "2013-05-31T18:48:02Z",
"closed_at": null,
"body": "We're considering putting multiple logical databases on the same physical server. \r\n\r\nIf we do that we will hit an issue where every app worker will have many connections to the same mysql server and reach the point of having context switching issues from the mysql perspective.\r\n\r\nWhat do you think about reusing db_charmer connections when there is multiple logical databases on the same physical server?\r\n\r\nIf this is not something you can add we may be doing it at Shopify and would be interested in your view on this & what you would consider to be the best approach.\r\n\r\nThanks\r\nTom"
},
{
"url": "https://api.github.com/repos/kovyrin/db-charmer/issues/69",
"labels_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/69/labels{/name}",
"comments_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/69/comments",
"events_url": "https://api.github.com/repos/kovyrin/db-charmer/issues/69/events",
"html_url": "https://github.com/kovyrin/db-charmer/issues/69",
"id": 14541052,
"number": 69,
"title": "execution expired - timing out getting connections - multi-threading issue",
"user": {
"login": "dashbitla",
"id": 114106,
"avatar_url": "https://avatars.githubusercontent.com/u/114106?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/dashbitla",
"html_url": "https://github.com/dashbitla",
"followers_url": "https://api.github.com/users/dashbitla/followers",
"following_url": "https://api.github.com/users/dashbitla/following{/other_user}",
"gists_url": "https://api.github.com/users/dashbitla/gists{/gist_id}",
"starred_url": "https://api.github.com/users/dashbitla/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/dashbitla/subscriptions",
"organizations_url": "https://api.github.com/users/dashbitla/orgs",
"repos_url": "https://api.github.com/users/dashbitla/repos",
"events_url": "https://api.github.com/users/dashbitla/events{/privacy}",
"received_events_url": "https://api.github.com/users/dashbitla/received_events",
"type": "User",
"site_admin": false
},
"labels": [
],
"state": "closed",
"locked": false,
"assignee": null,
"milestone": null,
"comments": 2,
"created_at": "2013-05-20T21:43:35Z",
"updated_at": "2013-11-10T15:52:05Z",
"closed_at": "2013-11-10T15:52:05Z",
"body": "2013-05-20T21:29:11Z 6058 TID-osusvs4o8 WARN: execution expired\r\n2013-05-20T21:29:11Z 6058 TID-osusvs4o8 WARN: /home/deployer/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/1.9.1/monitor.rb:185:in `lock'\r\n/home/deployer/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/1.9.1/monitor.rb:185:in `mon_enter'\r\n/home/deployer/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/1.9.1/monitor.rb:209:in `mon_synchronize'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:95:in `connection'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:404:in `retrieve_connection'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/connection_adapters/abstract/connection_specification.rb:170:in `retrieve_connection'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/connection_adapters/abstract/connection_specification.rb:144:in `connection'\r\n/home/deployer/apps/testapp.com/releases/20130519223524/vendor/gems/db-charmer-1.9.0/lib/db_charmer/active_record/connection_switching.rb:34:in `connection_with_magic'\r\n/home/deployer/apps/testapp.com/releases/20130519223524/vendor/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation_method.rb:15:in `block in relation_with_db_charmer'\r\n/home/deployer/apps/testapp.com/releases/20130519223524/vendor/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation_method.rb:14:in `tap'\r\n/home/deployer/apps/testapp.com/releases/20130519223524/vendor/gems/db-charmer-1.9.0/lib/db_charmer/rails3/active_record/relation_method.rb:14:in `relation_with_db_charmer'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/scoping/named.rb:37:in `scoped'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/querying.rb:9:in `select'\r\n/home/deployer/apps/testapp.com/releases/20130519223524/app/models/api_callback.rb:12:in `push'\r\n/home/deployer/apps/testapp.com/releases/20130519223524/app/workers/kiq_agent_callback.rb:9:in `perform'\r\n/home/deployer/apps/testapp.com/shared/bundle/ruby/1.9.1/gems/sidekiq-2.9.0/lib/sidekiq/processor.rb:49:in `block (3 levels)\r\n\r\n"
}
]
================================================
FILE: lib/db_charmer/action_controller/force_slave_reads.rb
================================================
module DbCharmer
module ActionController
module ForceSlaveReads
module ClassMethods
@@db_charmer_force_slave_reads_actions = {}
def force_slave_reads(params = {})
@@db_charmer_force_slave_reads_actions[self.name] = {
:except => params[:except] ? [*params[:except]].map(&:to_s) : [],
:only => params[:only] ? [*params[:only]].map(&:to_s) : []
}
end
def force_slave_reads_options
@@db_charmer_force_slave_reads_actions[self.name]
end
def force_slave_reads_action?(name = nil)
name = name.to_s
options = force_slave_reads_options
# If no options were defined for this controller, all actions are not forced to use slaves
return false unless options
# Actions where force_slave_reads mode was turned off
return false if options[:except].include?(name)
# Only for these actions force_slave_reads was turned on
return options[:only].include?(name) if options[:only].any?
# If :except is not empty, we're done with the checks and rest of the actions are should force slave reads
# Otherwise, all the actions are not in force_slave_reads mode
options[:except].any?
end
end
module InstanceMethods
DISPATCH_METHOD = (DbCharmer.rails3?) ? :process_action : :perform_action
def self.included(base)
base.alias_method_chain DISPATCH_METHOD, :forced_slave_reads
end
def force_slave_reads!
@db_charmer_force_slave_reads = true
end
def dont_force_slave_reads!
@db_charmer_force_slave_reads = false
end
def force_slave_reads?
@db_charmer_force_slave_reads || self.class.force_slave_reads_action?(params[:action])
end
protected
class_eval <<-EOF, __FILE__, __LINE__+1
def #{DISPATCH_METHOD}_with_forced_slave_reads(*args, &block)
DbCharmer.with_controller(self) do
#{DISPATCH_METHOD}_without_forced_slave_reads(*args, &block)
end
end
EOF
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/association_preload.rb
================================================
module DbCharmer
module ActiveRecord
module AssociationPreload
ASSOCIATION_TYPES = [ :has_one, :has_many, :belongs_to, :has_and_belongs_to_many ]
def self.extended(base)
ASSOCIATION_TYPES.each do |association_type|
base.class_eval <<-EOF, __FILE__, __LINE__ + 1
def self.preload_#{association_type}_association(records, reflection, preload_options = {})
if self.db_charmer_top_level_connection? || reflection.options[:polymorphic] ||
self.db_charmer_default_connection != reflection.klass.db_charmer_default_connection
return super(records, reflection, preload_options)
end
reflection.klass.on_db(self) do
super(records, reflection, preload_options)
end
end
EOF
end
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/class_attributes.rb
================================================
module DbCharmer
module ActiveRecord
module ClassAttributes
@@db_charmer_opts = {}
def db_charmer_opts=(opts)
@@db_charmer_opts[self.name] = opts
end
def db_charmer_opts
@@db_charmer_opts[self.name] || {}
end
#---------------------------------------------------------------------------------------------
@@db_charmer_default_connections = {}
def db_charmer_default_connection=(conn)
@@db_charmer_default_connections[self.name] = conn
end
def db_charmer_default_connection
@@db_charmer_default_connections[self.name]
end
#---------------------------------------------------------------------------------------------
@@db_charmer_slaves = {}
def db_charmer_slaves=(slaves)
@@db_charmer_slaves[self.name] = slaves
end
def db_charmer_slaves
@@db_charmer_slaves[self.name] || []
end
# Returns a random connection from the list of slaves configured for this AR class
def db_charmer_random_slave
return nil unless db_charmer_slaves.any?
db_charmer_slaves[rand(db_charmer_slaves.size)]
end
#---------------------------------------------------------------------------------------------
def db_charmer_connection_proxies
Thread.current[:db_charmer_connection_proxies] ||= {}
end
def db_charmer_connection_proxy=(proxy)
db_charmer_connection_proxies[self.name] = proxy
end
def db_charmer_connection_proxy
db_charmer_connection_proxies[self.name]
end
#---------------------------------------------------------------------------------------------
def db_charmer_force_slave_reads_flags
Thread.current[:db_charmer_force_slave_reads] ||= {}
end
def db_charmer_force_slave_reads=(force)
db_charmer_force_slave_reads_flags[self.name] = force
end
def db_charmer_force_slave_reads
db_charmer_force_slave_reads_flags[self.name]
end
# Slave reads are used in two cases:
# - per-model slave reads are enabled (see db_magic method for more details)
# - global slave reads enforcing is enabled (in a controller action)
def db_charmer_force_slave_reads?
db_charmer_force_slave_reads || DbCharmer.force_slave_reads?
end
#---------------------------------------------------------------------------------------------
def db_charmer_connection_levels
Thread.current[:db_charmer_connection_levels] ||= Hash.new(0)
end
def db_charmer_connection_level=(level)
db_charmer_connection_levels[self.name] = level
end
def db_charmer_connection_level
db_charmer_connection_levels[self.name] || 0
end
def db_charmer_top_level_connection?
db_charmer_connection_level.zero?
end
#---------------------------------------------------------------------------------------------
def db_charmer_remapped_connection
return nil unless db_charmer_top_level_connection?
name = :master
proxy = db_charmer_model_connection_proxy
name = proxy.db_charmer_connection_name.to_sym if proxy
remapped = db_charmer_database_remappings[name]
remapped ? DbCharmer::ConnectionFactory.connect(remapped, true) : nil
end
def db_charmer_database_remappings
Thread.current[:db_charmer_database_remappings] ||= Hash.new
end
def db_charmer_database_remappings=(mappings)
raise "Mappings must be nil or respond to []" if mappings && (! mappings.respond_to?(:[]))
Thread.current[:db_charmer_database_remappings] = mappings || {}
end
#---------------------------------------------------------------------------------------------
# Returns model-specific connection proxy, ignoring any global connection remappings
def db_charmer_model_connection_proxy
db_charmer_connection_proxy || db_charmer_default_connection
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/connection_switching.rb
================================================
module DbCharmer
module ActiveRecord
module ConnectionSwitching
def establish_real_connection_if_exists(name, should_exist = false)
name = name.to_s
# Check environment name
config = configurations[DbCharmer.env]
unless config
error = "Invalid environment name (does not exist in database.yml): #{DbCharmer.env}. Please set correct Rails.env or DbCharmer.env."
raise ArgumentError, error
end
# Check connection name
config = config[name]
unless config
if should_exist
raise ArgumentError, "Invalid connection name (does not exist in database.yml): #{DbCharmer.env}/#{name}"
end
return # No need to establish connection - they do not want us to
end
# Pass connection name with config
config[:connection_name] = name
establish_connection(config)
end
#-----------------------------------------------------------------------------------------------------------------
def hijack_connection!
return if self.respond_to?(:connection_with_magic)
class << self
# Make sure we check our accessors before going to the default connection retrieval method
def connection_with_magic
db_charmer_remapped_connection || db_charmer_model_connection_proxy || connection_without_magic
end
alias_method_chain :connection, :magic
def connection_pool_with_magic
if connection.respond_to?(:abstract_connection_class)
abstract_connection_class = connection.abstract_connection_class
connection_handler.retrieve_connection_pool(abstract_connection_class) || connection_pool_without_magic
else
connection_pool_without_magic
end
end
alias_method_chain :connection_pool, :magic
end
end
#-----------------------------------------------------------------------------------------------------------------
def coerce_to_connection_proxy(conn, should_exist = true)
# Return nil if given no connection specification
return nil if conn.nil?
# For sharded proxies just use them as-is
return conn if conn.respond_to?(:set_real_connection)
# For connection proxies and objects that could be coerced into a proxy just call the coercion method
return conn.db_charmer_connection_proxy if conn.respond_to?(:db_charmer_connection_proxy)
# For plain AR connection adapters, just use them as-is
return conn if conn.kind_of?(::ActiveRecord::ConnectionAdapters::AbstractAdapter)
# For connection names, use connection factory to create new connections
if conn.kind_of?(Symbol) || conn.kind_of?(String)
return DbCharmer::ConnectionFactory.connect(conn, should_exist)
end
# For connection configs (hashes), create connections
if conn.kind_of?(Hash)
conn = conn.symbolize_keys
raise ArgumentError, "Missing required :connection_name parameter" unless conn[:connection_name]
return DbCharmer::ConnectionFactory.connect_to_db(conn[:connection_name], conn)
end
# Fails for unsupported connection types
raise "Unsupported connection type: #{conn.class}"
end
#-----------------------------------------------------------------------------------------------------------------
def switch_connection_to(conn, should_exist = true)
new_conn = coerce_to_connection_proxy(conn, should_exist)
if db_charmer_connection_proxy.respond_to?(:set_real_connection)
db_charmer_connection_proxy.set_real_connection(new_conn)
end
self.db_charmer_connection_proxy = new_conn
self.hijack_connection!
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/db_magic.rb
================================================
module DbCharmer
module ActiveRecord
module DbMagic
def db_magic(opt = {})
# Make sure we could use our connections management here
hijack_connection!
# Should requested connections exist in the config?
should_exist = opt.has_key?(:should_exist) ? opt[:should_exist] : DbCharmer.connections_should_exist?
# Main connection management
setup_connection_magic(opt[:connection], should_exist)
# Set up slaves pool
opt[:slaves] ||= []
opt[:slaves] = [ opt[:slaves] ].flatten
opt[:slaves] << opt[:slave] if opt[:slave]
# Forced reads are enabled for all models by default, could be disabled by the user
forced_slave_reads = opt.has_key?(:force_slave_reads) ? opt[:force_slave_reads] : true
# Setup all the slaves related magic if needed
setup_slaves_magic(opt[:slaves], forced_slave_reads, should_exist)
# Setup inheritance magic
setup_children_magic(opt)
# Setup sharding if needed
if opt[:sharded]
raise ArgumentError, "Can't use sharding on a model with slaves!" if opt[:slaves].any?
setup_sharding_magic(opt[:sharded])
end
end
private
def setup_children_magic(opt)
self.db_charmer_opts = opt.clone
unless self.respond_to?(:inherited_with_db_magic)
class << self
def inherited_with_db_magic(child)
o = inherited_without_db_magic(child)
child.db_magic(self.db_charmer_opts)
o
end
alias_method_chain :inherited, :db_magic
end
end
end
def setup_sharding_magic(config)
# Add sharding-specific methods
self.extend(DbCharmer::ActiveRecord::Sharding)
# Get configuration
name = config[:sharded_connection] or raise ArgumentError, "No :sharded_connection!"
# Assign sharded connection
self.sharded_connection = DbCharmer::Sharding.sharded_connection(name)
# Setup model default connection
setup_connection_magic(sharded_connection.default_connection)
end
def setup_connection_magic(conn, should_exist = true)
conn_proxy = coerce_to_connection_proxy(conn, should_exist)
self.db_charmer_default_connection = conn_proxy
switch_connection_to(conn_proxy, should_exist)
end
def setup_slaves_magic(slaves, force_slave_reads, should_exist = true)
self.db_charmer_force_slave_reads = force_slave_reads
# Initialize the slave connections list
self.db_charmer_slaves = slaves.collect do |slave|
coerce_to_connection_proxy(slave, should_exist)
end
return if db_charmer_slaves.empty?
# Enable on_slave/on_master methods
self.extend(DbCharmer::ActiveRecord::MultiDbProxy::MasterSlaveClassMethods)
# Enable automatic master/slave queries routing (we have specialized versions on those modules for rails2/3)
self.extend(DbCharmer::ActiveRecord::MasterSlaveRouting::ClassMethods)
self.send(:include, DbCharmer::ActiveRecord::MasterSlaveRouting::InstanceMethods)
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/migration/multi_db_migrations.rb
================================================
module DbCharmer
module ActiveRecord
module Migration
module MultiDbMigrations
def self.append_features(base)
return false if base < self
super
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
base.class_eval do
if DbCharmer.rails31?
alias_method_chain :migrate, :db_wrapper
else
class << self
alias_method_chain :migrate, :db_wrapper
end
end
end
end
module ClassMethods
@@multi_db_names = {}
def multi_db_names
@@multi_db_names[self.name] || @@multi_db_names['ActiveRecord::Migration']
end
def multi_db_names=(names)
@@multi_db_names[self.name] = names
end
unless DbCharmer.rails31?
def migrate_with_db_wrapper(direction)
if names = multi_db_names
names.each do |multi_db_name|
on_db(multi_db_name) do
migrate_without_db_wrapper(direction)
end
end
else
migrate_without_db_wrapper(direction)
end
end
def on_db(db_name)
name = db_name.is_a?(Hash) ? db_name[:connection_name] : db_name.inspect
announce "Switching connection to #{name}"
# Switch connection
old_proxy = ::ActiveRecord::Base.db_charmer_connection_proxy
db_name = nil if db_name == :default
::ActiveRecord::Base.switch_connection_to(db_name, DbCharmer.connections_should_exist?)
# Yield the block
yield
ensure
# Switch it back
::ActiveRecord::Base.verify_active_connections!
announce "Switching connection back"
::ActiveRecord::Base.switch_connection_to(old_proxy)
end
end
def db_magic(opts = {})
# Collect connections from all possible options
conns = [ opts[:connection], opts[:connections] ]
conns << shard_connections(opts[:sharded_connection]) if opts[:sharded_connection]
# Get a unique set of connections
conns = conns.flatten.compact.uniq
raise ArgumentError, "No connection name - no magic!" unless conns.any?
# Save connections
self.multi_db_names = conns
end
# Return a list of connections to shards in a sharded connection
def shard_connections(conn_name)
conn = DbCharmer::Sharding.sharded_connection(conn_name)
conn.shard_connections
end
end
def migrate_with_db_wrapper(direction)
if names = self.class.multi_db_names
names.each do |multi_db_name|
on_db(multi_db_name) do
migrate_without_db_wrapper(direction)
end
end
else
migrate_without_db_wrapper(direction)
end
end
def record_on_db(db_name, block)
recorder = ::ActiveRecord::Migration::CommandRecorder.new(DbCharmer::ConnectionFactory.connect(db_name))
old_recorder, @connection = @connection, recorder
block.call
old_recorder.record :on_db, [db_name, @connection]
@connection = old_recorder
end
def replay_commands_on_db(name, commands)
on_db(name) do
commands.each do |cmd, args|
send(cmd, *args)
end
end
end
def on_db(db_name, &block)
if @connection.is_a?(::ActiveRecord::Migration::CommandRecorder)
record_on_db(db_name, block)
return
end
name = db_name.is_a?(Hash) ? db_name[:connection_name] : db_name.inspect
announce "Switching connection to #{name}"
# Switch connection
old_connection, old_proxy = @connection, ::ActiveRecord::Base.db_charmer_connection_proxy
db_name = nil if db_name == :default
::ActiveRecord::Base.switch_connection_to(db_name, DbCharmer.connections_should_exist?)
# Yield the block
::ActiveRecord::Base.connection_pool.with_connection do |conn|
@connection = conn
yield
end
ensure
@connection = old_connection
# Switch it back
::ActiveRecord::Base.verify_active_connections!
announce "Switching connection back"
::ActiveRecord::Base.switch_connection_to(old_proxy)
end
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/multi_db_proxy.rb
================================================
module DbCharmer
module ActiveRecord
module MultiDbProxy
# Simple proxy class that switches connections and then proxies all the calls
# This class is used to implement chained on_db calls
class OnDbProxy < ActiveSupport::BasicObject
# We need to do this because in Rails 2.3 BasicObject does not remove object_id method, which is stupid
undef_method(:object_id) if instance_methods.member?('object_id')
def initialize(proxy_target, slave)
@proxy_target = proxy_target
@slave = slave
end
private
def method_missing(meth, *args, &block)
# Switch connection and proxy the method call
@proxy_target.on_db(@slave) do |proxy_target|
res = proxy_target.__send__(meth, *args, &block)
# If result is a scope/association, return a new proxy for it, otherwise return the result itself
(res.proxy?) ? OnDbProxy.new(res, @slave) : res
end
end
end
module ClassMethods
def on_db(con, proxy_target = nil)
proxy_target ||= self
# Chain call
return OnDbProxy.new(proxy_target, con) unless block_given?
# Block call
begin
self.db_charmer_connection_level += 1
old_proxy = db_charmer_connection_proxy
switch_connection_to(con, DbCharmer.connections_should_exist?)
yield(proxy_target)
ensure
switch_connection_to(old_proxy)
self.db_charmer_connection_level -= 1
end
end
end
module InstanceMethods
def on_db(con, proxy_target = nil, &block)
proxy_target ||= self
self.class.on_db(con, proxy_target, &block)
end
end
module MasterSlaveClassMethods
def on_slave(con = nil, proxy_target = nil, &block)
con ||= db_charmer_random_slave
raise ArgumentError, "No slaves found in the class and no slave connection given" unless con
on_db(con, proxy_target, &block)
end
def on_master(proxy_target = nil, &block)
on_db(db_charmer_default_connection, proxy_target, &block)
end
def first_level_on_slave
first_level = db_charmer_top_level_connection? && on_master.connection.open_transactions.zero?
if first_level && db_charmer_force_slave_reads? && db_charmer_slaves.any?
on_slave { yield }
else
yield
end
end
end
end
end
end
================================================
FILE: lib/db_charmer/active_record/sharding.rb
================================================
module DbCharmer
module ActiveRecord
module Sharding
def self.extended(model)
model.cattr_accessor(:sharded_connection)
end
def shard_for(key, proxy_target = nil, &block)
raise ArgumentError, "No sharded connection configured!" unless sharded_connection
conn = sharded_connection.sharder.shard_for_key(key)
on_db(conn, proxy_target, &block)
end
# Run on default shard (if supported by the sharding method)
def on_default_shard(proxy_target = nil, &block)
raise ArgumentError, "No sharded connection configured!" unless sharded_connection
if sharded_connection.support_default_shard?
shard_for(:default, proxy_target, &block)
else
raise ArgumentError, "This model's sharding method does not support default shard"
end
end
# Enumerate shards
def on_each_shard(proxy_target = nil, &block)
raise ArgumentError, "No sharded connection configured!" unless sharded_connection
conns = sharded_connection.shard_connections
raise ArgumentError, "This model's sharding method does not support shards enumeration" unless conns
conns.each do |conn|
on_db(conn, proxy_target, &block)
end
end
end
end
end
================================================
FILE: lib/db_charmer/connection_factory.rb
================================================
#
# 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.
#
module DbCharmer
module ConnectionFactory
def self.connection_classes
Thread.current[:db_charmer_generated_connection_classes] ||= {}
end
def self.connection_classes=(val)
Thread.current[:db_charmer_generated_connection_classes] = val
end
def self.reset!
self.connection_classes = {}
end
# Establishes connection or return an existing one from cache
def self.connect(connection_name, should_exist = true)
connection_name = connection_name.to_s
connection_classes[connection_name] ||= establish_connection(connection_name, should_exist)
end
# Establishes connection or return an existing one from cache (not using AR database configs)
def self.connect_to_db(connection_name, config)
connection_name = connection_name.to_s
connection_classes[connection_name] ||= establish_connection_to_db(connection_name, config)
end
# Establish connection with a specified name
def self.establish_connection(connection_name, should_exist = true)
abstract_class = generate_abstract_class(connection_name, should_exist)
DbCharmer::ConnectionProxy.new(abstract_class, connection_name)
end
# Establish connection with a specified name (not using AR database configs)
def self.establish_connection_to_db(connection_name, config)
abstract_class = generate_abstract_class_for_db(connection_name, config)
DbCharmer::ConnectionProxy.new(abstract_class, connection_name)
end
# Generate an abstract AR class with specified connection established
def self.generate_abstract_class(connection_name, should_exist = true)
# Generate class
klass = generate_empty_abstract_ar_class(abstract_connection_class_name(connection_name))
# Establish connection
klass.establish_real_connection_if_exists(connection_name.to_sym, !!should_exist)
# Return the class
return klass
end
# Generate an abstract AR class with specified connection established (not using AR database configs)
def self.generate_abstract_class_for_db(connection_name, config)
# Generate class
klass = generate_empty_abstract_ar_class(abstract_connection_class_name(connection_name))
# Establish connection
klass.establish_connection(config)
# Return the class
return klass
end
def self.generate_empty_abstract_ar_class(klass)
# Define class
module_eval "class #{klass} < ::ActiveRecord::Base; self.abstract_class = true; end"
# Return class
klass.constantize
end
# Generates unique names for our abstract AR classes
def self.abstract_connection_class_name(connection_name)
conn_name_klass = connection_name.to_s.gsub(/\W+/, '_').camelize
thread = Thread.current.object_id.abs # need to make sure it is non-negative
"::AutoGeneratedAbstractConnectionClass#{conn_name_klass}ForThread#{thread}"
end
end
end
================================================
FILE: lib/db_charmer/connection_proxy.rb
================================================
# Simple proxy that sends all method calls to a real database connection
module DbCharmer
class ConnectionProxy < ActiveSupport::BasicObject
# We need to do this because in Rails 2.3 BasicObject does not remove object_id method, which is stupid
undef_method(:object_id) if instance_methods.member?('object_id')
# We use this to get a connection class from the proxy
attr_accessor :abstract_connection_class
def initialize(abstract_class, db_name)
@abstract_connection_class = abstract_class
@db_name = db_name
end
def db_charmer_connection_name
@db_name
end
def db_charmer_connection_proxy
self
end
def db_charmer_retrieve_connection
@abstract_connection_class.retrieve_connection
end
def nil?
false
end
#-----------------------------------------------------------------------------------------------
RESPOND_TO_METHODS = [
:abstract_connection_class,
:db_charmer_connection_name,
:db_charmer_connection_proxy,
:db_charmer_retrieve_connection,
:nil?
].freeze
# Short-circuit some of the methods for which we know there is a separate check in coercion code
DOESNT_RESPOND_TO_METHODS = [
:set_real_connection
].freeze
def respond_to?(method_name, include_all = false)
return true if RESPOND_TO_METHODS.include?(method_name)
return false if DOESNT_RESPOND_TO_METHODS.include?(method_name)
db_charmer_retrieve_connection.respond_to?(method_name, include_all)
end
#-----------------------------------------------------------------------------------------------
def method_missing(meth, *args, &block)
db_charmer_retrieve_connection.send(meth, *args, &block)
end
end
end
================================================
FILE: lib/db_charmer/core_extensions.rb
================================================
class Object
unless defined?(try)
def try(method, *options, &block)
send(method, *options, &block)
end
end
# These methods are added to all objects so we could call proxy? on anything
# and figure if an object is a proxy w/o hitting method_missing or respond_to?
def self.proxy?
false
end
def proxy?
false
end
end
class NilClass
def try(*args)
nil
end
end
================================================
FILE: lib/db_charmer/force_slave_reads.rb
================================================
module DbCharmer
def self.current_controller
Thread.current[:db_charmer_current_controller]
end
def self.current_controller=(val)
Thread.current[:db_charmer_current_controller] = val
end
#-------------------------------------------------------------------------------------------------
def self.forced_slave_reads_setting
Thread.current[:db_charmer_forced_slave_reads]
end
def self.forced_slave_reads_setting=(val)
Thread.current[:db_charmer_forced_slave_reads] = val
end
#-------------------------------------------------------------------------------------------------
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
#-------------------------------------------------------------------------------------------------
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
#-------------------------------------------------------------------------------------------------
# Force all reads in a block of code to go to a slave
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
end
================================================
FILE: lib/db_charmer/rails2/abstract_adapter/log_formatting.rb
================================================
module DbCharmer
module AbstractAdapter
module LogFormatting
def self.included(base)
base.alias_method_chain :format_log_entry, :connection_name
end
def connection_name
raise "Can't find connection configuration!" unless @config
@config[:connection_name]
end
# Rails 2.X specific logging method
def format_log_entry_with_connection_name(message, dump = nil)
msg = connection_name ? "[#{connection_name}] " : ''
msg = " \e[0;34;1m#{msg}\e[0m" if connection_name && ::ActiveRecord::Base.colorize_logging
msg << format_log_entry_without_connection_name(message, dump)
end
end
end
end
================================================
FILE: lib/db_charmer/rails2/active_record/master_slave_routing.rb
================================================
module DbCharmer
module ActiveRecord
module MasterSlaveRouting
module ClassMethods
SLAVE_METHODS = [ :find_by_sql, :count_by_sql, :calculate ]
MASTER_METHODS = [ :update, :create, :delete, :destroy, :delete_all, :destroy_all, :update_all, :update_counters ]
SLAVE_METHODS.each do |slave_method|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{slave_method}(*args, &block)
first_level_on_slave do
super(*args, &block)
end
end
EOF
end
MASTER_METHODS.each do |master_method|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{master_method}(*args, &block)
on_master do
super(*args, &block)
end
end
EOF
end
def find(*args, &block)
options = args.last
if options.is_a?(Hash) && options[:lock]
on_master { super(*args, &block) }
else
super(*args, &block)
end
end
end
module InstanceMethods
def reload(*args, &block)
self.class.on_master do
super(*args, &block)
end
end
end
end
end
end
================================================
FILE: lib/db_charmer/rails2/active_record/named_scope/scope_proxy.rb
================================================
module DbCharmer
module ActiveRecord
module NamedScope
module ScopeProxy
def proxy?
true
end
def on_db(con, proxy_target = nil, &block)
proxy_target ||= self
proxy_scope.on_db(con, proxy_target, &block)
end
def on_slave(con = nil, &block)
proxy_scope.on_slave(con, self, &block)
end
def on_master(&block)
proxy_scope.on_master(self, &block)
end
end
end
end
end
================================================
FILE: lib/db_charmer/rails3/abstract_adapter/connection_name.rb
================================================
module DbCharmer
module AbstractAdapter
module ConnectionName
# We use this proxy to push connection name down to instrumenters w/o monkey-patching the log method itself
class InstrumenterDecorator < ActiveSupport::BasicObject
def initialize(adapter, instrumenter)
@adapter = adapter
@instrumenter = instrumenter
end
def instrument(name, payload = {}, &block)
payload[:connection_name] ||= @adapter.connection_name
@instrumenter.instrument(name, payload, &block)
end
def method_missing(meth, *args, &block)
@instrumenter.send(meth, *args, &block)
end
end
def self.included(base)
base.alias_method_chain :initialize, :connection_name
end
def connection_name
raise "Can't find connection configuration!" unless @config
@config[:connection_name]
end
def initialize_with_connection_name(*args)
initialize_without_connection_name(*args)
@instrumenter = InstrumenterDecorator.new(self, @instrumenter)
end
end
end
end
================================================
FILE: lib/db_charmer/rails3/active_record/log_subscriber.rb
================================================
module DbCharmer
module ActiveRecord
module LogSubscriber
def self.included(base)
base.send(:attr_accessor, :connection_name)
base.alias_method_chain :sql, :connection_name
base.alias_method_chain :debug, :connection_name
end
def sql_with_connection_name(event)
self.connection_name = event.payload[:connection_name]
sql_without_connection_name(event)
end
def debug_with_connection_name(msg)
conn = connection_name ? color(" [#{connection_name}]", ActiveSupport::LogSubscriber::BLUE, true) : ''
debug_without_connection_name(conn + msg)
end
end
end
end
================================================
FILE: lib/db_charmer/rails3/active_record/master_slave_routing.rb
================================================
module DbCharmer
module ActiveRecord
module MasterSlaveRouting
module ClassMethods
SLAVE_METHODS = [ :find_by_sql, :count_by_sql ]
MASTER_METHODS = [ ] # I don't know any methods in AR::Base that change data directly w/o going to the relation object
SLAVE_METHODS.each do |slave_method|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{slave_method}(*args, &block)
first_level_on_slave do
super(*args, &block)
end
end
EOF
end
MASTER_METHODS.each do |master_method|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{master_method}(*args, &block)
on_master do
super(*args, &block)
end
end
EOF
end
end
module InstanceMethods
MASTER_METHODS = [ :reload ]
MASTER_METHODS.each do |master_method|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{master_method}(*args, &block)
self.class.on_master do
super(*args, &block)
end
end
EOF
end
end
end
end
end
================================================
FILE: lib/db_charmer/rails3/active_record/relation/connection_routing.rb
================================================
module DbCharmer
module ActiveRecord
module Relation
module ConnectionRouting
# All the methods that could be querying the database
SLAVE_METHODS = [ :calculate, :exists? ]
MASTER_METHODS = [ :delete, :delete_all, :destroy, :destroy_all, :reload, :update, :update_all ]
ALL_METHODS = SLAVE_METHODS + MASTER_METHODS
DB_CHARMER_ATTRIBUTES = [ :db_charmer_connection, :db_charmer_connection_is_forced, :db_charmer_enable_slaves ]
# Define the default relation connection + override all the query methods here
def self.included(base)
init_attributes(base)
init_routing(base)
end
# Define our attributes + spawn methods shit needs to be changed to make sure our accessors are copied over to the new instances
def self.init_attributes(base)
DB_CHARMER_ATTRIBUTES.each do |attr|
base.send(:attr_accessor, attr)
end
# Override spawn methods
base.alias_method_chain :except, :db_charmer
base.alias_method_chain :only, :db_charmer
end
# Override all query methods
def self.init_routing(base)
ALL_METHODS.each do |meth|
base.alias_method_chain meth, :db_charmer
end
# Special case: for normal selects we go to the slave, but for selects with a lock we should use master
base.alias_method_chain :to_a, :db_charmer
end
# Copy db_charmer attributes in addition to what they're copying
def except_with_db_charmer(*args)
except_without_db_charmer(*args).tap do |result|
copy_db_charmer_options(self, result)
end
end
# Copy db_charmer attributes in addition to what they're copying
def only_with_db_charmer(*args)
only_without_db_charmer(*args).tap do |result|
copy_db_charmer_options(self, result)
end
end
# Copy our accessors from one instance to another
def copy_db_charmer_options(src, dst)
DB_CHARMER_ATTRIBUTES.each do |attr|
dst.send("#{attr}=".to_sym, src.send(attr))
end
end
# Connection switching (changes the default relation connection)
def on_db(con, &block)
if block_given?
@klass.on_db(con, &block)
else
clone.tap do |result|
result.db_charmer_connection = con
result.db_charmer_connection_is_forced = true
end
end
end
# Make sure we get the right connection here
def connection
@klass.on_db(db_charmer_connection).connection
end
# Selects preferred destination (master/slave/default) for a query
def select_destination(method, recommendation = :default)
# If this relation was created within a forced connection block (e.g Model.on_db(:foo).relation)
# Then we should use that connection everywhere except cases when a model is slave-enabled
# in those cases DML queries go to the master
if db_charmer_connection_is_forced
return :master if db_charmer_enable_slaves && MASTER_METHODS.member?(method)
return :default
end
# If this relation is created from a slave-enabled model, let's do the routing if possible
if db_charmer_enable_slaves
return :slave if SLAVE_METHODS.member?(method)
return :master if MASTER_METHODS.member?(method)
else
# Make sure we do not use recommended destination
recommendation = :default
end
# If nothing else came up, let's use the default or recommended connection
return recommendation
end
# Switch the model to default relation connection
def switch_connection_for_method(method, recommendation = nil)
# Choose where to send the query
destination ||= select_destination(method, recommendation)
# What method to use
on_db_method = [ :on_db, db_charmer_connection ]
on_db_method = :on_master if destination == :master
on_db_method = :first_level_on_slave if destination == :slave
# Perform the query
@klass.send(*on_db_method) do
yield
end
end
# For normal selects we go to the slave, but for selects with a lock we should use master
def to_a_with_db_charmer(*args, &block)
preferred_destination = :slave
preferred_destination = :master if lock_value
switch_connection_for_method(:to_a, preferred_destination) do
to_a_without_db_charmer(*args, &block)
end
end
# Need this to mimick alias_method_chain name generation (exists? => exists_with_db_charmer?)
def self.aliased_method_name(target, with)
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
"#{aliased_target}_#{with}_db_charmer#{punctuation}"
end
# Override all the query methods here
ALL_METHODS.each do |method|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{aliased_method_name method, :with}(*args, &block)
switch_connection_for_method(:#{method.to_s}) do
#{aliased_method_name method, :without}(*args, &block)
end
end
EOF
end
end
end
end
end
================================================
FILE: lib/db_charmer/rails3/active_record/relation_method.rb
================================================
module DbCharmer
module ActiveRecord
module RelationMethod
def self.extended(base)
class << base
alias_method_chain :relation, :db_charmer
alias_method_chain :arel_engine, :db_charmer
end
end
# Create a relation object and initialize its default connection
def relation_with_db_charmer(*args, &block)
relation_without_db_charmer(*args, &block).tap do |rel|
rel.db_charmer_connection = self.connection
rel.db_charmer_enable_slaves = self.db_charmer_slaves.any?
rel.db_charmer_connection_is_forced = !db_charmer_top_level_connection?
end
end
# Use the model itself an engine for Arel, do not fall back to AR::Base
def arel_engine_with_db_charmer(*)
self
end
end
end
end
================================================
FILE: lib/db_charmer/rails31/active_record/migration/command_recorder.rb
================================================
module DbCharmer
module ActiveRecord
module Migration
module CommandRecorder
def invert_on_db(args)
[:replay_commands_on_db, [args.first, args[1].inverse]]
end
end
end
end
end
================================================
FILE: lib/db_charmer/rails31/active_record/preloader/association.rb
================================================
module DbCharmer
module ActiveRecord
module Preloader
module Association
extend ActiveSupport::Concern
included do
alias_method_chain :build_scope, :db_magic
end
def build_scope_with_db_magic
if model.db_charmer_top_level_connection? || reflection.options[:polymorphic] ||
model.db_charmer_default_connection != klass.db_charmer_default_connection
build_scope_without_db_magic
else
build_scope_without_db_magic.on_db(model)
end
end
end
end
end
end
================================================
FILE: lib/db_charmer/rails31/active_record/preloader/has_and_belongs_to_many.rb
================================================
module DbCharmer
module ActiveRecord
module Preloader
module HasAndBelongsToMany
extend ActiveSupport::Concern
included do
alias_method_chain :records_for, :db_magic
end
def records_for_with_db_magic(ids)
if model.db_charmer_top_level_connection? || reflection.options[:polymorphic] ||
model.db_charmer_default_connection != klass.db_charmer_default_connection
records_for_without_db_magic(ids)
else
klass.on_db(model) do
records_for_without_db_magic(ids)
end
end
end
end
end
end
end
================================================
FILE: lib/db_charmer/railtie.rb
================================================
module DbCharmer
class Railtie < Rails::Railtie
rake_tasks do
load "db_charmer/tasks/databases.rake"
end
end
end
================================================
FILE: lib/db_charmer/sharding/connection.rb
================================================
module DbCharmer
module Sharding
class Connection
attr_accessor :config, :sharder
def initialize(config)
@config = config
@sharder = self.instantiate_sharder
end
def instantiate_sharder
raise ArgumentError, "No :method passed!" unless config[:method]
sharder_class_name = "DbCharmer::Sharding::Method::#{config[:method].to_s.classify}"
sharder_class = sharder_class_name.constantize
sharder_class.new(config)
end
def shard_connections
sharder.respond_to?(:shard_connections) ? sharder.shard_connections : nil
end
def support_default_shard?
sharder.respond_to?(:support_default_shard?) && sharder.support_default_shard?
end
def default_connection
@default_connection ||= DbCharmer::Sharding::StubConnection.new(self)
end
end
end
end
================================================
FILE: lib/db_charmer/sharding/method/db_block_group_map.rb
================================================
# 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
# 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
#---------------------------------------------------------------------------------------------------------------
# Sharder name
attr_accessor :name
# Mapping db connection
attr_accessor :connection, :connection_name
# Mapping table name
attr_accessor :map_table
# Tablegroups table name
attr_accessor :groups_table
# Shards table name
attr_accessor :shards_table
# Sharding keys block size
attr_accessor :block_size
def initialize(config)
@name = config[:name] or raise(ArgumentError, "Missing required :name parameter!")
@connection = DbCharmer::ConnectionFactory.connect(config[:connection], true)
@block_size = (config[:block_size] || 10000).to_i
@map_table = config[:map_table] or raise(ArgumentError, "Missing required :map_table parameter!")
@groups_table = config[:groups_table] or raise(ArgumentError, "Missing required :groups_table parameter!")
@shards_table = config[:shards_table] or raise(ArgumentError, "Missing required :shards_table parameter!")
# Local caches
@shard_info_cache = {}
@group_info_cache = {}
@blocks_cache = Rails.cache
@blocks_cache_prefix = config[:blocks_cache_prefix] || "#{@name}_block:"
end
#---------------------------------------------------------------------------------------------------------------
def shard_for_key(key)
block = block_for_key(key)
# Auto-allocate new blocks
block ||= allocate_new_block_for_key(key)
raise ArgumentError, "Invalid key value, no shards found for this key and could not create a new block!" unless block
# Load shard
group_id = block['group_id'].to_i
shard_info = shard_info_by_group_id(group_id)
# Get config
shard_connection_config(shard_info, group_id)
end
#---------------------------------------------------------------------------------------------------------------
# Returns a block for a key
def block_for_key(key, cache = true)
# Cleanup the cache if asked to
key_range = [ block_start_for_key(key), block_end_for_key(key) ]
block_cache_key = "%d-%d" % key_range
if cache
cached_block = get_cached_block(block_cache_key)
return cached_block if cached_block
end
# Fetch cached value or load from db
block = begin
sql = "SELECT * FROM #{map_table} WHERE start_id = #{key_range.first} AND end_id = #{key_range.last} LIMIT 1"
connection.select_one(sql, 'Find a shard block')
end
set_cached_block(block_cache_key, block)
return block
end
#---------------------------------------------------------------------------------------------------------------
def get_cached_block(block_cache_key)
@blocks_cache.read("#{@blocks_cache_prefix}#{block_cache_key}")
end
def set_cached_block(block_cache_key, block)
@blocks_cache.write("#{@blocks_cache_prefix}#{block_cache_key}", block)
end
#---------------------------------------------------------------------------------------------------------------
# Load group info
def group_info_by_id(group_id, cache = true)
# Cleanup the cache if asked to
@group_info_cache[group_id] = nil unless cache
# Either load from cache or from db
@group_info_cache[group_id] ||= begin
prepare_shard_models
Group.find_by_id(group_id)
end
end
# Load shard info
def shard_info_by_id(shard_id, cache = true)
# Cleanup the cache if asked to
@shard_info_cache[shard_id] = nil unless cache
# Either load from cache or from db
@shard_info_cache[shard_id] ||= begin
prepare_shard_models
Shard.find_by_id(shard_id)
end
end
# Load shard info using mapping info for a group
def shard_info_by_group_id(group_id)
# Load group
group_info = group_info_by_id(group_id)
raise ArgumentError, "Invalid group_id: #{group_id}" unless group_info
shard_info = shard_info_by_id(group_info.shard_id)
raise ArgumentError, "Invalid shard_id: #{group_info.shard_id}" unless shard_info
return shard_info
end
#---------------------------------------------------------------------------------------------------------------
def allocate_new_block_for_key(key)
# Can't find any groups to use for blocks allocation!
return nil unless group = least_loaded_group
# Figure out block limits
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 IGNORE INTO #{map_table}
SET start_id = #{start_id},
end_id = #{end_id},
group_id = #{group.id},
block_size = #{block_size},
created_at = NOW(),
updated_at = NOW()
SQL
connection.execute(sql, "Allocate new block")
# Increment the blocks counter on the shard
Group.update_counters(group.id, :blocks_count => +1)
# Retry block search after creation
block_for_key(key)
end
def least_loaded_group
prepare_shard_models
# Select group
group = Group.first(:conditions => { :enabled => true, :open => true }, :order => 'blocks_count ASC')
raise "Can't find any tablegroups to use for blocks allocation!" unless group
return group
end
#---------------------------------------------------------------------------------------------------------------
def block_start_for_key(key)
block_size.to_i * (key.to_i / block_size.to_i)
end
def block_end_for_key(key)
block_size.to_i + block_start_for_key(key)
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 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
# Prepare model for working with our shards table
def prepare_shard_models
Shard.set_table_name(shards_table)
Shard.switch_connection_to(connection)
Group.set_table_name(groups_table)
Group.switch_connection_to(connection)
end
end
end
end
end
================================================
FILE: lib/db_charmer/sharding/method/db_block_map.rb
================================================
# 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.
#
module DbCharmer
module Sharding
module Method
class DbBlockMap
# Sharder name
attr_accessor :name
# Mapping db connection
attr_accessor :connection, :connection_name
# Mapping table name
attr_accessor :map_table
# Shards table name
attr_accessor :shards_table
# Sharding keys block size
attr_accessor :block_size
def initialize(config)
@name = config[:name] or raise(ArgumentError, "Missing required :name parameter!")
@connection = DbCharmer::ConnectionFactory.connect(config[:connection], true)
@block_size = (config[:block_size] || 10000).to_i
@map_table = config[:map_table] or raise(ArgumentError, "Missing required :map_table parameter!")
@shards_table = config[:shards_table] or raise(ArgumentError, "Missing required :shards_table parameter!")
# Local caches
@shard_info_cache = {}
@blocks_cache = Rails.cache
@blocks_cache_prefix = config[:blocks_cache_prefix] || "#{@name}_block:"
end
def shard_for_key(key)
block = block_for_key(key)
begin
# Auto-allocate new blocks
block ||= allocate_new_block_for_key(key)
rescue ::ActiveRecord::StatementInvalid => e
raise unless e.message.include?('Duplicate entry')
block = block_for_key(key)
end
raise ArgumentError, "Invalid key value, no shards found for this key and could not create a new block!" unless block
# Bail if no shard found
shard_id = block['shard_id'].to_i
shard_info = shard_info_by_id(shard_id)
raise ArgumentError, "Invalid shard_id: #{shard_id}" unless shard_info
# Get config
shard_connection_config(shard_info)
end
class ShardInfo < ::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
end
# Returns a block for a key
def block_for_key(key, cache = true)
# Cleanup the cache if asked to
key_range = [ block_start_for_key(key), block_end_for_key(key) ]
block_cache_key = "%d-%d" % key_range
if cache
cached_block = get_cached_block(block_cache_key)
return cached_block if cached_block
end
# Fetch cached value or load from db
block = begin
sql = "SELECT * FROM #{map_table} WHERE start_id = #{key_range.first} AND end_id = #{key_range.last} LIMIT 1"
connection.select_one(sql, 'Find a shard block')
end
set_cached_block(block_cache_key, block)
return block
end
def get_cached_block(block_cache_key)
@blocks_cache.read("#{@blocks_cache_prefix}#{block_cache_key}")
end
def set_cached_block(block_cache_key, block)
@blocks_cache.write("#{@blocks_cache_prefix}#{block_cache_key}", block)
end
# Load shard info
def shard_info_by_id(shard_id, cache = true)
# Cleanup the cache if asked to
@shard_info_cache[shard_id] = nil unless cache
# Either load from cache or from db
@shard_info_cache[shard_id] ||= begin
prepare_shard_model
ShardInfo.find_by_id(shard_id)
end
end
def allocate_new_block_for_key(key)
# Can't find any shards to use for blocks allocation!
return nil unless shard = least_loaded_shard
# Figure out block limits
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}
SET start_id = #{start_id},
end_id = #{end_id},
shard_id = #{shard.id},
block_size = #{block_size},
created_at = NOW(),
updated_at = NOW()
SQL
connection.execute(sql, "Allocate new block")
# Increment the blocks counter on the shard
ShardInfo.update_counters(shard.id, :blocks_count => +1)
# Retry block search after creation
block_for_key(key)
end
def least_loaded_shard
prepare_shard_model
# Select shard
shard = ShardInfo.all(:conditions => { :enabled => true, :open => true }, :order => 'blocks_count ASC', :limit => 1).first
raise "Can't find any shards to use for blocks allocation!" unless shard
return shard
end
def block_start_for_key(key)
block_size.to_i * (key.to_i / block_size.to_i)
end
def block_end_for_key(key)
block_size.to_i + block_start_for_key(key)
end
# Create configuration (use mapping connection as a template)
def shard_connection_config(shard)
# Format connection name
shard_name = "db_charmer_db_block_map_#{name}_shard_%05d" % shard.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 => shard.db_name
)
end
def create_shard(params)
params = params.symbolize_keys
[ :db_host, :db_port, :db_user, :db_pass, :db_name ].each do |arg|
raise ArgumentError, "Missing required parameter: #{arg}" unless params[arg]
end
# Prepare model
prepare_shard_model
# Create the record
ShardInfo.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 = params[:db_name]
end
end
def shard_connections
# Find all shards
prepare_shard_model
shards = ShardInfo.all(:conditions => { :enabled => true })
# Map them to connections
shards.map { |shard| shard_connection_config(shard) }
end
# Prepare model for working with our shards table
def prepare_shard_model
ShardInfo.table_name = shards_table
ShardInfo.switch_connection_to(connection)
end
end
end
end
end
================================================
FILE: lib/db_charmer/sharding/method/hash_map.rb
================================================
module DbCharmer
module Sharding
module Method
class HashMap
attr_accessor :map
def initialize(config)
@map = config[:map].clone or raise ArgumentError, "No :map defined!"
end
def shard_for_key(key)
res = map[key] || map[:default]
raise ArgumentError, "Invalid key value, no shards found for this key!" unless res
return res
end
def support_default_shard?
map.has_key?(:default)
end
end
end
end
end
================================================
FILE: lib/db_charmer/sharding/method/range.rb
================================================
module DbCharmer
module Sharding
module Method
class Range
attr_accessor :ranges
def initialize(config)
@ranges = config[:ranges] ? config[:ranges].clone : raise(ArgumentError, "No :ranges defined!")
end
def shard_for_key(key)
return ranges[:default] if key == :default
ranges.each do |range, shard|
next if range == :default
return shard if range.member?(key.to_i)
end
return ranges[:default] if ranges[:default]
raise ArgumentError, "Invalid key value, no shards found for this key!"
end
def support_default_shard?
ranges.has_key?(:default)
end
def shard_connections
ranges.values.uniq
end
end
end
end
end
================================================
FILE: lib/db_charmer/sharding/method.rb
================================================
module DbCharmer
module Sharding
module Method
autoload :Range, 'db_charmer/sharding/method/range'
autoload :HashMap, 'db_charmer/sharding/method/hash_map'
autoload :DbBlockMap, 'db_charmer/sharding/method/db_block_map'
autoload :DbBlockGroupMap, 'db_charmer/sharding/method/db_block_group_map'
end
end
end
================================================
FILE: lib/db_charmer/sharding/stub_connection.rb
================================================
# 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.
#
module DbCharmer
module Sharding
class StubConnection
attr_accessor :sharded_connection
def initialize(sharded_connection)
@sharded_connection = sharded_connection
@real_conn = nil
end
def set_real_connection(real_conn)
@real_conn = real_conn
end
def db_charmer_connection_name
"StubConnection"
end
def real_connection
# Return memoized real connection
return @real_conn if @real_conn
# If sharded connection supports shards enumeration, get the first shard
conn = sharded_connection.shard_connections.try(:first)
# If we do not have real connection yet, try to use the default one (if it is supported by the sharder)
conn ||= sharded_connection.sharder.shard_for_key(:default) if sharded_connection.support_default_shard?
# Get connection proxy for our real connection
return nil unless conn
@real_conn = ::ActiveRecord::Base.coerce_to_connection_proxy(conn, DbCharmer.connections_should_exist?)
end
def respond_to?(method_name, include_all = false)
return true if super
return false if real_connection.object_id == self.object_id
real_connection.respond_to?(method_name, include_all)
end
def method_missing(meth, *args, &block)
# Fail on database statements
if ::ActiveRecord::ConnectionAdapters::DatabaseStatements.instance_methods.member?(meth.to_s)
raise ::ActiveRecord::ConnectionNotEstablished, "You have to switch connection on your model before using it!"
end
# Fail if no connection has been established yet
unless real_connection
raise ::ActiveRecord::ConnectionNotEstablished, "No real connection to proxy this method to!"
end
if real_connection.kind_of?(DbCharmer::Sharding::StubConnection)
raise ::ActiveRecord::ConnectionNotEstablished, "You have to switch connection on your model before using it!"
end
# Proxy the call to our real connection target
real_connection.__send__(meth, *args, &block)
end
end
end
end
================================================
FILE: lib/db_charmer/sharding.rb
================================================
module DbCharmer
module Sharding
autoload :Connection, 'db_charmer/sharding/connection'
autoload :StubConnection, 'db_charmer/sharding/stub_connection'
autoload :Method, 'db_charmer/sharding/method'
@@sharded_connections = {}
def self.register_connection(config)
name = config[:name] or raise ArgumentError, "No :name in connection!"
@@sharded_connections[name] = DbCharmer::Sharding::Connection.new(config)
end
def self.sharded_connection(name)
@@sharded_connections[name] or raise ArgumentError, "Invalid sharded connection name!"
end
end
end
================================================
FILE: lib/db_charmer/tasks/databases.rake
================================================
namespace :db_charmer do
namespace :create do
desc 'Create all the local databases defined in config/database.yml'
task :all => "db:load_config" do
::ActiveRecord::Base.configurations.each_value do |config|
# Skip entries that don't have a database key, such as the first entry here:
#
# defaults: &defaults
# adapter: mysql
# username: root
# password:
# host: localhost
#
# development:
# database: blog_development
# <<: *defaults
next unless config['database']
# Only connect to local databases
local_database?(config) { create_core_and_sub_database(config) }
end
end
end
desc 'Create the databases defined in config/database.yml for the current RAILS_ENV'
task :create => "db:load_config" do
create_core_and_sub_database(ActiveRecord::Base.configurations[RAILS_ENV])
end
def create_core_and_sub_database(config)
create_database(config)
config.each_value do | sub_config |
next unless sub_config.is_a?(Hash)
next unless sub_config['database']
create_database(sub_config)
end
end
namespace :drop do
desc 'Drops all the local databases defined in config/database.yml'
task :all => "db:load_config" do
::ActiveRecord::Base.configurations.each_value do |config|
# Skip entries that don't have a database key
next unless config['database']
# Only connect to local databases
local_database?(config) { drop_core_and_sub_database(config) }
end
end
end
desc 'Drops the database for the current RAILS_ENV'
task :drop => "db:load_config" do
config = ::ActiveRecord::Base.configurations[RAILS_ENV || 'development']
begin
drop_core_and_sub_database(config)
rescue Exception => e
puts "Couldn't drop #{config['database']} : #{e.inspect}"
end
end
def local_database?(config, &block)
if %w( 127.0.0.1 localhost ).include?(config['host']) || config['host'].blank?
yield
else
puts "This task only modifies local databases. #{config['database']} is on a remote host."
end
end
end
def drop_core_and_sub_database(config)
begin
drop_database(config)
rescue
$stderr.puts "#{config['database']} not exists"
end
config.each_value do | sub_config |
next unless sub_config.is_a?(Hash)
next unless sub_config['database']
begin
drop_database(sub_config)
rescue
$stderr.puts "#{config['database']} not exists"
end
end
end
================================================
FILE: lib/db_charmer/version.rb
================================================
module DbCharmer
module Version
MAJOR = 1
MINOR = 9
PATCH = 1
BUILD = nil
STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
end
end
================================================
FILE: lib/db_charmer/with_remapped_databases.rb
================================================
module DbCharmer
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
def self.hijack_new_classes?
!! Thread.current[:db_charmer_hijack_new_classes]
end
private
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
end
#---------------------------------------------------------------------------------------------------
# Hijack connection on all new AR classes when we're in a block with main AR connection remapped
class ActiveRecord::Base
class << self
def inherited_with_hijacking(subclass)
out = inherited_without_hijacking(subclass)
hijack_connection! if DbCharmer.hijack_new_classes?
out
end
alias_method_chain :inherited, :hijacking
end
end
================================================
FILE: lib/db_charmer.rb
================================================
# In Rails 2.2 they did not add it to the autoload so it won't work w/o this require
require 'active_record/version' unless defined?(::ActiveRecord::VERSION::MAJOR)
require 'active_support/core_ext'
#---------------------------------------------------------------------------------------------------
module DbCharmer
# Configure autoload
autoload :Sharding, 'db_charmer/sharding'
autoload :Version, 'db_charmer/version'
module ActionController
autoload :ForceSlaveReads, 'db_charmer/action_controller/force_slave_reads'
end
#-------------------------------------------------------------------------------------------------
# Used in all Rails3-specific places
def self.rails3?
::ActiveRecord::VERSION::MAJOR > 2
end
# Used in all Rails3.1-specific places
def self.rails31?
rails3? && ::ActiveRecord::VERSION::MINOR >= 1
end
# Used in all Rails2-specific places
def self.rails2?
::ActiveRecord::VERSION::MAJOR == 2
end
# Detect broken Rails version
def self.rails324?
ActiveRecord::VERSION::STRING == '3.2.4'
end
#-------------------------------------------------------------------------------------------------
# Returns true if we're running within a Rails project
def self.running_with_rails?
defined?(Rails) && Rails.respond_to?(:env)
end
# Returns current environment name based on Rails or Rack environment variables
def self.detect_environment
return Rails.env if running_with_rails?
ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
end
# Try to detect current environment or use development by default
@@env = DbCharmer.detect_environment
mattr_accessor :env
#-------------------------------------------------------------------------------------------------
# Accessors
@@connections_should_exist = true
mattr_accessor :connections_should_exist
def self.connections_should_exist?
!! connections_should_exist
end
#-------------------------------------------------------------------------------------------------
def self.logger
return Rails.logger if running_with_rails?
@@logger ||= Logger.new(STDERR)
end
#-------------------------------------------------------------------------------------------------
# Extend ActionController to support forcing slave reads
def self.enable_controller_magic!
::ActionController::Base.extend(DbCharmer::ActionController::ForceSlaveReads::ClassMethods)
::ActionController::Base.send(:include, DbCharmer::ActionController::ForceSlaveReads::InstanceMethods)
end
end
#---------------------------------------------------------------------------------------------------
# Print warning about the broken Rails 2.3.4
puts "WARNING: Rails 3.2.4 is not officially supported by DbCharmer. Please upgrade." if DbCharmer.rails324?
#---------------------------------------------------------------------------------------------------
# Add useful methods to global object
require 'db_charmer/core_extensions'
require 'db_charmer/connection_factory'
require 'db_charmer/connection_proxy'
require 'db_charmer/force_slave_reads'
require 'db_charmer/with_remapped_databases'
if DbCharmer.rails3?
require "db_charmer/railtie"
end
#---------------------------------------------------------------------------------------------------
# Add our custom class-level attributes to AR models
require 'db_charmer/active_record/class_attributes'
require 'active_record'
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::ClassAttributes)
#---------------------------------------------------------------------------------------------------
# Enable connections switching in AR
require 'db_charmer/active_record/connection_switching'
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::ConnectionSwitching)
#---------------------------------------------------------------------------------------------------
# Enable AR logging extensions
if DbCharmer.rails3?
require 'db_charmer/rails3/abstract_adapter/connection_name'
require 'db_charmer/rails3/active_record/log_subscriber'
ActiveRecord::LogSubscriber.send(:include, DbCharmer::ActiveRecord::LogSubscriber)
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, DbCharmer::AbstractAdapter::ConnectionName)
else
require 'db_charmer/rails2/abstract_adapter/log_formatting'
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, DbCharmer::AbstractAdapter::LogFormatting)
end
#---------------------------------------------------------------------------------------------------
# Enable connection proxy in AR
require 'db_charmer/active_record/multi_db_proxy'
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::MultiDbProxy::ClassMethods)
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::MultiDbProxy::MasterSlaveClassMethods)
ActiveRecord::Base.send(:include, DbCharmer::ActiveRecord::MultiDbProxy::InstanceMethods)
#---------------------------------------------------------------------------------------------------
# Enable connection proxy for relations
if DbCharmer.rails3?
require 'db_charmer/rails3/active_record/relation_method'
require 'db_charmer/rails3/active_record/relation/connection_routing'
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::RelationMethod)
ActiveRecord::Relation.send(:include, DbCharmer::ActiveRecord::Relation::ConnectionRouting)
end
#---------------------------------------------------------------------------------------------------
# Enable connection proxy for scopes (rails 2.x only)
if DbCharmer.rails2?
require 'db_charmer/rails2/active_record/named_scope/scope_proxy'
ActiveRecord::NamedScope::Scope.send(:include, DbCharmer::ActiveRecord::NamedScope::ScopeProxy)
end
#---------------------------------------------------------------------------------------------------
# Enable connection proxy for associations
# WARNING: Inject methods to association class right here because they proxy +include+ calls
# somewhere else, which means we could not use +include+ method here
association_proxy_class = DbCharmer.rails31? ? ActiveRecord::Associations::CollectionProxy :
ActiveRecord::Associations::AssociationProxy
association_proxy_class.class_eval do
def proxy?
true
end
if DbCharmer.rails31?
def on_db(con, proxy_target = nil, &block)
proxy_target ||= self
@association.klass.on_db(con, proxy_target, &block)
end
def on_slave(con = nil, &block)
@association.klass.on_slave(con, self, &block)
end
def on_master(&block)
@association.klass.on_master(self, &block)
end
else
def on_db(con, proxy_target = nil, &block)
proxy_target ||= self
@reflection.klass.on_db(con, proxy_target, &block)
end
def on_slave(con = nil, &block)
@reflection.klass.on_slave(con, self, &block)
end
def on_master(&block)
@reflection.klass.on_master(self, &block)
end
end
end
#---------------------------------------------------------------------------------------------------
# Enable multi-db migrations
require 'db_charmer/active_record/migration/multi_db_migrations'
ActiveRecord::Migration.send(:include, DbCharmer::ActiveRecord::Migration::MultiDbMigrations)
if DbCharmer.rails31?
require 'db_charmer/rails31/active_record/migration/command_recorder'
ActiveRecord::Migration::CommandRecorder.send(:include, DbCharmer::ActiveRecord::Migration::CommandRecorder)
end
#---------------------------------------------------------------------------------------------------
# Enable the magic
if DbCharmer.rails3?
require 'db_charmer/rails3/active_record/master_slave_routing'
else
require 'db_charmer/rails2/active_record/master_slave_routing'
end
require 'db_charmer/active_record/sharding'
require 'db_charmer/active_record/db_magic'
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::DbMagic)
#---------------------------------------------------------------------------------------------------
# Setup association preload magic
if DbCharmer.rails31?
require 'db_charmer/rails31/active_record/preloader/association'
ActiveRecord::Associations::Preloader::Association.send(:include, DbCharmer::ActiveRecord::Preloader::Association)
require 'db_charmer/rails31/active_record/preloader/has_and_belongs_to_many'
ActiveRecord::Associations::Preloader::HasAndBelongsToMany.send(:include, DbCharmer::ActiveRecord::Preloader::HasAndBelongsToMany)
else
require 'db_charmer/active_record/association_preload'
ActiveRecord::Base.extend(DbCharmer::ActiveRecord::AssociationPreload)
# Open up really useful API method
ActiveRecord::AssociationPreload::ClassMethods.send(:public, :preload_associations)
end
================================================
FILE: test-project/.gitignore
================================================
log/*.log
db/schema.*
.idea
TAGS
config/database.yml
.bundle
tmp
.DS_Store
vendor
Gemfile.lock
doc
================================================
FILE: test-project/.rspec
================================================
--colour
--format documentation
================================================
FILE: test-project/Gemfile
================================================
source 'http://rubygems.org'
gem 'rake', "0.9.2.2"
gem 'mysql', "2.8.1"
gem 'rspec', '< 3.0'
gem 'rspec-core', '< 3.0'
gem 'rspec-rails', '< 3.0'
# Load DbCharmer as a gem
if ENV['DB_CHARMER_GEM'].to_s == ''
gem_path = File.expand_path(File.dirname(File.dirname(__FILE__)))
puts "Using on-disk db-charmer code from '#{gem_path}'..."
gem 'db-charmer', :path => gem_path, :require => 'db_charmer'
else
puts "Using db-charmer gem: #{ENV['DB_CHARMER_GEM']}..."
gem 'db-charmer', ENV['DB_CHARMER_GEM'], :require => 'db_charmer'
end
# Detect Rails version we need to use
rails_version_file = File.expand_path("../.rails-version", __FILE__)
version = File.exists?(rails_version_file) && File.read(rails_version_file).chomp
version ||= ENV['RAILS_VERSION']
version ||= '3-2-stable'
# Require gems for selected rails version
case version
when /master/
gem "rails", :git => "git://github.com/rails/rails.git"
gem "arel", :git => "git://github.com/rails/arel.git"
gem "journey", :git => "git://github.com/rails/journey.git"
when /3-0-stable/
gem "rails", :git => "git://github.com/rails/rails.git", :branch => "3-0-stable"
gem "arel", :git => "git://github.com/rails/arel.git", :branch => "2-0-stable"
when /3-1-stable/
gem "rails", :git => "git://github.com/rails/rails.git", :branch => "3-1-stable"
when /3-2-stable/
gem "rails", :git => "git://github.com/rail
gitextract_9iqagwm9/
├── .gitignore
├── .travis.yml
├── CHANGES
├── LICENSE
├── Makefile
├── README.rdoc
├── Rakefile
├── ci_build
├── db-charmer.gemspec
├── init.rb
├── issues/
│ └── issues-as-of-2014-11-14.json
├── lib/
│ ├── db_charmer/
│ │ ├── action_controller/
│ │ │ └── force_slave_reads.rb
│ │ ├── active_record/
│ │ │ ├── association_preload.rb
│ │ │ ├── class_attributes.rb
│ │ │ ├── connection_switching.rb
│ │ │ ├── db_magic.rb
│ │ │ ├── migration/
│ │ │ │ └── multi_db_migrations.rb
│ │ │ ├── multi_db_proxy.rb
│ │ │ └── sharding.rb
│ │ ├── connection_factory.rb
│ │ ├── connection_proxy.rb
│ │ ├── core_extensions.rb
│ │ ├── force_slave_reads.rb
│ │ ├── rails2/
│ │ │ ├── abstract_adapter/
│ │ │ │ └── log_formatting.rb
│ │ │ └── active_record/
│ │ │ ├── master_slave_routing.rb
│ │ │ └── named_scope/
│ │ │ └── scope_proxy.rb
│ │ ├── rails3/
│ │ │ ├── abstract_adapter/
│ │ │ │ └── connection_name.rb
│ │ │ └── active_record/
│ │ │ ├── log_subscriber.rb
│ │ │ ├── master_slave_routing.rb
│ │ │ ├── relation/
│ │ │ │ └── connection_routing.rb
│ │ │ └── relation_method.rb
│ │ ├── rails31/
│ │ │ └── active_record/
│ │ │ ├── migration/
│ │ │ │ └── command_recorder.rb
│ │ │ └── preloader/
│ │ │ ├── association.rb
│ │ │ └── has_and_belongs_to_many.rb
│ │ ├── railtie.rb
│ │ ├── sharding/
│ │ │ ├── connection.rb
│ │ │ ├── method/
│ │ │ │ ├── db_block_group_map.rb
│ │ │ │ ├── db_block_map.rb
│ │ │ │ ├── hash_map.rb
│ │ │ │ └── range.rb
│ │ │ ├── method.rb
│ │ │ └── stub_connection.rb
│ │ ├── sharding.rb
│ │ ├── tasks/
│ │ │ └── databases.rake
│ │ ├── version.rb
│ │ └── with_remapped_databases.rb
│ └── db_charmer.rb
├── test-project/
│ ├── .gitignore
│ ├── .rspec
│ ├── Gemfile
│ ├── Rakefile
│ ├── TODO
│ ├── app/
│ │ ├── controllers/
│ │ │ ├── application_controller.rb
│ │ │ └── posts_controller.rb
│ │ ├── helpers/
│ │ │ └── application_helper.rb
│ │ ├── models/
│ │ │ ├── avatar.rb
│ │ │ ├── car.rb
│ │ │ ├── categories_posts.rb
│ │ │ ├── category.rb
│ │ │ ├── comment.rb
│ │ │ ├── event.rb
│ │ │ ├── ford.rb
│ │ │ ├── house.rb
│ │ │ ├── log_record.rb
│ │ │ ├── post.rb
│ │ │ ├── range_sharded_model.rb
│ │ │ ├── toyota.rb
│ │ │ └── user.rb
│ │ └── views/
│ │ ├── layouts/
│ │ │ └── application.html.erb
│ │ └── posts/
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── config/
│ │ ├── application.rb
│ │ ├── boot.rb
│ │ ├── database.yml.example
│ │ ├── environment.rb
│ │ ├── environments/
│ │ │ └── test.rb
│ │ ├── initializers/
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── db_charmer.rb
│ │ │ ├── secret_token.rb
│ │ │ ├── session_store.rb
│ │ │ └── sharding.rb
│ │ ├── locales/
│ │ │ └── en.yml
│ │ └── routes.rb
│ ├── db/
│ │ ├── create_databases.sql
│ │ ├── migrate/
│ │ │ ├── 20090810013829_create_log_records.rb
│ │ │ ├── 20090810013922_create_posts.rb
│ │ │ ├── 20090810221944_create_users.rb
│ │ │ ├── 20100305234245_create_categories.rb
│ │ │ ├── 20100305234340_create_categories_posts.rb
│ │ │ ├── 20100305235831_create_avatars.rb
│ │ │ ├── 20100328201317_create_sharding_map_tables.rb
│ │ │ ├── 20100330180517_create_event_tables.rb
│ │ │ ├── 20100817191548_create_cars.rb
│ │ │ └── 20111005193941_create_comments.rb
│ │ ├── seeds.rb
│ │ └── sharding.sql
│ └── spec/
│ ├── controllers/
│ │ └── posts_controller_spec.rb
│ ├── fixtures/
│ │ ├── avatars.yml
│ │ ├── categories.yml
│ │ ├── categories_posts.yml
│ │ ├── comments.yml
│ │ ├── event_shards_info.yml
│ │ ├── event_shards_map.yml
│ │ ├── log_records.yml
│ │ ├── posts.yml
│ │ └── users.yml
│ ├── integration/
│ │ └── multi_threading_spec.rb
│ ├── models/
│ │ ├── avatar_spec.rb
│ │ ├── cars_spec.rb
│ │ ├── categories_posts_spec.rb
│ │ ├── category_spec.rb
│ │ ├── comment_spec.rb
│ │ ├── event_spec.rb
│ │ ├── log_record_spec.rb
│ │ ├── post_spec.rb
│ │ ├── range_sharded_model_spec.rb
│ │ └── user_spec.rb
│ ├── sharding/
│ │ ├── connection_spec.rb
│ │ ├── method/
│ │ │ ├── db_block_map_spec.rb
│ │ │ ├── hash_map_spec.rb
│ │ │ └── range_spec.rb
│ │ └── sharding_spec.rb
│ ├── spec_helper.rb
│ ├── support/
│ │ └── rails31_stub_connection.rb
│ └── unit/
│ ├── abstract_adapter/
│ │ └── log_formatting_spec.rb
│ ├── action_controller/
│ │ └── force_slave_reads_spec.rb
│ ├── active_record/
│ │ ├── association_preload_spec.rb
│ │ ├── association_proxy_spec.rb
│ │ ├── class_attributes_spec.rb
│ │ ├── connection_switching_spec.rb
│ │ ├── db_magic_spec.rb
│ │ ├── master_slave_routing_spec.rb
│ │ ├── migration/
│ │ │ └── multi_db_migrations_spec.rb
│ │ ├── named_scope/
│ │ │ └── named_scope_spec.rb
│ │ └── relation_spec.rb
│ ├── connection_factory_spec.rb
│ ├── connection_proxy_spec.rb
│ ├── db_charmer_spec.rb
│ ├── multi_db_proxy_spec.rb
│ └── with_remapped_databases_spec.rb
└── test-project-2.x/
├── Gemfile
├── Rakefile
├── config/
│ ├── boot.rb
│ ├── database.yml.example
│ ├── environment.rb
│ ├── environments/
│ │ └── test.rb
│ ├── initializers/
│ │ ├── backtrace_silencers.rb
│ │ ├── db_charmer.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── new_rails_defaults.rb
│ │ ├── session_store.rb
│ │ └── sharding.rb
│ ├── locales/
│ │ └── en.yml
│ ├── preinitializer.rb
│ └── routes.rb
├── script/
│ └── console
└── spec/
├── spec.opts
└── spec_helper.rb
SYMBOL INDEX (437 symbols across 77 files)
FILE: lib/db_charmer.rb
type DbCharmer (line 6) | module DbCharmer
type ActionController (line 10) | module ActionController
function rails3? (line 16) | def self.rails3?
function rails31? (line 21) | def self.rails31?
function rails2? (line 26) | def self.rails2?
function rails324? (line 31) | def self.rails324?
function running_with_rails? (line 37) | def self.running_with_rails?
function detect_environment (line 42) | def self.detect_environment
function connections_should_exist? (line 56) | def self.connections_should_exist?
function logger (line 61) | def self.logger
function enable_controller_magic! (line 68) | def self.enable_controller_magic!
function proxy? (line 144) | def proxy?
function on_db (line 149) | def on_db(con, proxy_target = nil, &block)
function on_slave (line 154) | def on_slave(con = nil, &block)
function on_master (line 158) | def on_master(&block)
function on_db (line 162) | def on_db(con, proxy_target = nil, &block)
function on_slave (line 167) | def on_slave(con = nil, &block)
function on_master (line 171) | def on_master(&block)
FILE: lib/db_charmer/action_controller/force_slave_reads.rb
type DbCharmer (line 1) | module DbCharmer
type ActionController (line 2) | module ActionController
type ForceSlaveReads (line 3) | module ForceSlaveReads
type ClassMethods (line 5) | module ClassMethods
function force_slave_reads (line 7) | def force_slave_reads(params = {})
function force_slave_reads_options (line 14) | def force_slave_reads_options
function force_slave_reads_action? (line 18) | def force_slave_reads_action?(name = nil)
type InstanceMethods (line 37) | module InstanceMethods
function included (line 40) | def self.included(base)
function force_slave_reads! (line 44) | def force_slave_reads!
function dont_force_slave_reads! (line 48) | def dont_force_slave_reads!
function force_slave_reads? (line 52) | def force_slave_reads?
FILE: lib/db_charmer/active_record/association_preload.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type AssociationPreload (line 3) | module AssociationPreload
function extended (line 6) | def self.extended(base)
FILE: lib/db_charmer/active_record/class_attributes.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type ClassAttributes (line 3) | module ClassAttributes
function db_charmer_opts= (line 5) | def db_charmer_opts=(opts)
function db_charmer_opts (line 9) | def db_charmer_opts
function db_charmer_default_connection= (line 15) | def db_charmer_default_connection=(conn)
function db_charmer_default_connection (line 19) | def db_charmer_default_connection
function db_charmer_slaves= (line 25) | def db_charmer_slaves=(slaves)
function db_charmer_slaves (line 29) | def db_charmer_slaves
function db_charmer_random_slave (line 34) | def db_charmer_random_slave
function db_charmer_connection_proxies (line 40) | def db_charmer_connection_proxies
function db_charmer_connection_proxy= (line 44) | def db_charmer_connection_proxy=(proxy)
function db_charmer_connection_proxy (line 48) | def db_charmer_connection_proxy
function db_charmer_force_slave_reads_flags (line 53) | def db_charmer_force_slave_reads_flags
function db_charmer_force_slave_reads= (line 57) | def db_charmer_force_slave_reads=(force)
function db_charmer_force_slave_reads (line 61) | def db_charmer_force_slave_reads
function db_charmer_force_slave_reads? (line 68) | def db_charmer_force_slave_reads?
function db_charmer_connection_levels (line 73) | def db_charmer_connection_levels
function db_charmer_connection_level= (line 77) | def db_charmer_connection_level=(level)
function db_charmer_connection_level (line 81) | def db_charmer_connection_level
function db_charmer_top_level_connection? (line 85) | def db_charmer_top_level_connection?
function db_charmer_remapped_connection (line 90) | def db_charmer_remapped_connection
function db_charmer_database_remappings (line 100) | def db_charmer_database_remappings
function db_charmer_database_remappings= (line 104) | def db_charmer_database_remappings=(mappings)
function db_charmer_model_connection_proxy (line 111) | def db_charmer_model_connection_proxy
FILE: lib/db_charmer/active_record/connection_switching.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type ConnectionSwitching (line 3) | module ConnectionSwitching
function establish_real_connection_if_exists (line 4) | def establish_real_connection_if_exists(name, should_exist = false)
function hijack_connection! (line 29) | def hijack_connection!
function coerce_to_connection_proxy (line 51) | def coerce_to_connection_proxy(conn, should_exist = true)
function switch_connection_to (line 81) | def switch_connection_to(conn, should_exist = true)
FILE: lib/db_charmer/active_record/db_magic.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type DbMagic (line 3) | module DbMagic
function db_magic (line 5) | def db_magic(opt = {})
function setup_children_magic (line 38) | def setup_children_magic(opt)
function setup_sharding_magic (line 53) | def setup_sharding_magic(config)
function setup_connection_magic (line 66) | def setup_connection_magic(conn, should_exist = true)
function setup_slaves_magic (line 72) | def setup_slaves_magic(slaves, force_slave_reads, should_exist = t...
FILE: lib/db_charmer/active_record/migration/multi_db_migrations.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type Migration (line 3) | module Migration
type MultiDbMigrations (line 4) | module MultiDbMigrations
function append_features (line 6) | def self.append_features(base)
type ClassMethods (line 22) | module ClassMethods
function multi_db_names (line 24) | def multi_db_names
function multi_db_names= (line 28) | def multi_db_names=(names)
function migrate_with_db_wrapper (line 33) | def migrate_with_db_wrapper(direction)
function on_db (line 45) | def on_db(db_name)
function db_magic (line 62) | def db_magic(opts = {})
function shard_connections (line 76) | def shard_connections(conn_name)
function migrate_with_db_wrapper (line 82) | def migrate_with_db_wrapper(direction)
function record_on_db (line 94) | def record_on_db(db_name, block)
function replay_commands_on_db (line 102) | def replay_commands_on_db(name, commands)
function on_db (line 110) | def on_db(db_name, &block)
FILE: lib/db_charmer/active_record/multi_db_proxy.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type MultiDbProxy (line 3) | module MultiDbProxy
class OnDbProxy (line 6) | class OnDbProxy < ActiveSupport::BasicObject
method initialize (line 10) | def initialize(proxy_target, slave)
method method_missing (line 17) | def method_missing(meth, *args, &block)
type ClassMethods (line 28) | module ClassMethods
function on_db (line 29) | def on_db(con, proxy_target = nil)
type InstanceMethods (line 48) | module InstanceMethods
function on_db (line 49) | def on_db(con, proxy_target = nil, &block)
type MasterSlaveClassMethods (line 55) | module MasterSlaveClassMethods
function on_slave (line 56) | def on_slave(con = nil, proxy_target = nil, &block)
function on_master (line 62) | def on_master(proxy_target = nil, &block)
function first_level_on_slave (line 66) | def first_level_on_slave
FILE: lib/db_charmer/active_record/sharding.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type Sharding (line 3) | module Sharding
function extended (line 5) | def self.extended(model)
function shard_for (line 9) | def shard_for(key, proxy_target = nil, &block)
function on_default_shard (line 16) | def on_default_shard(proxy_target = nil, &block)
function on_each_shard (line 27) | def on_each_shard(proxy_target = nil, &block)
FILE: lib/db_charmer/connection_factory.rb
type DbCharmer (line 7) | module DbCharmer
type ConnectionFactory (line 8) | module ConnectionFactory
function connection_classes (line 9) | def self.connection_classes
function connection_classes= (line 13) | def self.connection_classes=(val)
function reset! (line 17) | def self.reset!
function connect (line 22) | def self.connect(connection_name, should_exist = true)
function connect_to_db (line 28) | def self.connect_to_db(connection_name, config)
function establish_connection (line 34) | def self.establish_connection(connection_name, should_exist = true)
function establish_connection_to_db (line 40) | def self.establish_connection_to_db(connection_name, config)
function generate_abstract_class (line 46) | def self.generate_abstract_class(connection_name, should_exist = true)
function generate_abstract_class_for_db (line 58) | def self.generate_abstract_class_for_db(connection_name, config)
function generate_empty_abstract_ar_class (line 69) | def self.generate_empty_abstract_ar_class(klass)
function abstract_connection_class_name (line 78) | def self.abstract_connection_class_name(connection_name)
FILE: lib/db_charmer/connection_proxy.rb
type DbCharmer (line 2) | module DbCharmer
class ConnectionProxy (line 3) | class ConnectionProxy < ActiveSupport::BasicObject
method initialize (line 10) | def initialize(abstract_class, db_name)
method db_charmer_connection_name (line 15) | def db_charmer_connection_name
method db_charmer_connection_proxy (line 19) | def db_charmer_connection_proxy
method db_charmer_retrieve_connection (line 23) | def db_charmer_retrieve_connection
method nil? (line 27) | def nil?
method respond_to? (line 45) | def respond_to?(method_name, include_all = false)
method method_missing (line 52) | def method_missing(meth, *args, &block)
FILE: lib/db_charmer/core_extensions.rb
class Object (line 1) | class Object
method try (line 3) | def try(method, *options, &block)
method proxy? (line 10) | def self.proxy?
method proxy? (line 14) | def proxy?
class NilClass (line 19) | class NilClass
method try (line 20) | def try(*args)
FILE: lib/db_charmer/force_slave_reads.rb
type DbCharmer (line 1) | module DbCharmer
function current_controller (line 2) | def self.current_controller
function current_controller= (line 6) | def self.current_controller=(val)
function forced_slave_reads_setting (line 11) | def self.forced_slave_reads_setting
function forced_slave_reads_setting= (line 15) | def self.forced_slave_reads_setting=(val)
function force_slave_reads? (line 20) | def self.force_slave_reads?
function with_controller (line 33) | def self.with_controller(controller)
function force_slave_reads (line 45) | def self.force_slave_reads
FILE: lib/db_charmer/rails2/abstract_adapter/log_formatting.rb
type DbCharmer (line 1) | module DbCharmer
type AbstractAdapter (line 2) | module AbstractAdapter
type LogFormatting (line 3) | module LogFormatting
function included (line 5) | def self.included(base)
function connection_name (line 9) | def connection_name
function format_log_entry_with_connection_name (line 15) | def format_log_entry_with_connection_name(message, dump = nil)
FILE: lib/db_charmer/rails2/active_record/master_slave_routing.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type MasterSlaveRouting (line 3) | module MasterSlaveRouting
type ClassMethods (line 5) | module ClassMethods
function find (line 29) | def find(*args, &block)
type InstanceMethods (line 39) | module InstanceMethods
function reload (line 40) | def reload(*args, &block)
FILE: lib/db_charmer/rails2/active_record/named_scope/scope_proxy.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type NamedScope (line 3) | module NamedScope
type ScopeProxy (line 4) | module ScopeProxy
function proxy? (line 6) | def proxy?
function on_db (line 10) | def on_db(con, proxy_target = nil, &block)
function on_slave (line 15) | def on_slave(con = nil, &block)
function on_master (line 19) | def on_master(&block)
FILE: lib/db_charmer/rails3/abstract_adapter/connection_name.rb
type DbCharmer (line 1) | module DbCharmer
type AbstractAdapter (line 2) | module AbstractAdapter
type ConnectionName (line 3) | module ConnectionName
class InstrumenterDecorator (line 6) | class InstrumenterDecorator < ActiveSupport::BasicObject
method initialize (line 7) | def initialize(adapter, instrumenter)
method instrument (line 12) | def instrument(name, payload = {}, &block)
method method_missing (line 17) | def method_missing(meth, *args, &block)
function included (line 22) | def self.included(base)
function connection_name (line 26) | def connection_name
function initialize_with_connection_name (line 31) | def initialize_with_connection_name(*args)
FILE: lib/db_charmer/rails3/active_record/log_subscriber.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type LogSubscriber (line 3) | module LogSubscriber
function included (line 5) | def self.included(base)
function sql_with_connection_name (line 11) | def sql_with_connection_name(event)
function debug_with_connection_name (line 16) | def debug_with_connection_name(msg)
FILE: lib/db_charmer/rails3/active_record/master_slave_routing.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type MasterSlaveRouting (line 3) | module MasterSlaveRouting
type ClassMethods (line 5) | module ClassMethods
type InstanceMethods (line 30) | module InstanceMethods
FILE: lib/db_charmer/rails3/active_record/relation/connection_routing.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type Relation (line 3) | module Relation
type ConnectionRouting (line 4) | module ConnectionRouting
function included (line 14) | def self.included(base)
function init_attributes (line 20) | def self.init_attributes(base)
function init_routing (line 31) | def self.init_routing(base)
function except_with_db_charmer (line 41) | def except_with_db_charmer(*args)
function only_with_db_charmer (line 48) | def only_with_db_charmer(*args)
function copy_db_charmer_options (line 55) | def copy_db_charmer_options(src, dst)
function on_db (line 62) | def on_db(con, &block)
function connection (line 74) | def connection
function select_destination (line 79) | def select_destination(method, recommendation = :default)
function switch_connection_for_method (line 102) | def switch_connection_for_method(method, recommendation = nil)
function to_a_with_db_charmer (line 118) | def to_a_with_db_charmer(*args, &block)
function aliased_method_name (line 128) | def self.aliased_method_name(target, with)
FILE: lib/db_charmer/rails3/active_record/relation_method.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type RelationMethod (line 3) | module RelationMethod
function extended (line 5) | def self.extended(base)
function relation_with_db_charmer (line 13) | def relation_with_db_charmer(*args, &block)
function arel_engine_with_db_charmer (line 22) | def arel_engine_with_db_charmer(*)
FILE: lib/db_charmer/rails31/active_record/migration/command_recorder.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type Migration (line 3) | module Migration
type CommandRecorder (line 4) | module CommandRecorder
function invert_on_db (line 5) | def invert_on_db(args)
FILE: lib/db_charmer/rails31/active_record/preloader/association.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type Preloader (line 3) | module Preloader
type Association (line 4) | module Association
function build_scope_with_db_magic (line 10) | def build_scope_with_db_magic
FILE: lib/db_charmer/rails31/active_record/preloader/has_and_belongs_to_many.rb
type DbCharmer (line 1) | module DbCharmer
type ActiveRecord (line 2) | module ActiveRecord
type Preloader (line 3) | module Preloader
type HasAndBelongsToMany (line 4) | module HasAndBelongsToMany
function records_for_with_db_magic (line 10) | def records_for_with_db_magic(ids)
FILE: lib/db_charmer/railtie.rb
type DbCharmer (line 1) | module DbCharmer
class Railtie (line 2) | class Railtie < Rails::Railtie
FILE: lib/db_charmer/sharding.rb
type DbCharmer (line 1) | module DbCharmer
type Sharding (line 2) | module Sharding
function register_connection (line 9) | def self.register_connection(config)
function sharded_connection (line 14) | def self.sharded_connection(name)
FILE: lib/db_charmer/sharding/connection.rb
type DbCharmer (line 1) | module DbCharmer
type Sharding (line 2) | module Sharding
class Connection (line 3) | class Connection
method initialize (line 6) | def initialize(config)
method instantiate_sharder (line 11) | def instantiate_sharder
method shard_connections (line 18) | def shard_connections
method support_default_shard? (line 22) | def support_default_shard?
method default_connection (line 26) | def default_connection
FILE: lib/db_charmer/sharding/method.rb
type DbCharmer (line 1) | module DbCharmer
type Sharding (line 2) | module Sharding
type Method (line 3) | module Method
FILE: lib/db_charmer/sharding/method/db_block_group_map.rb
type DbCharmer (line 8) | module DbCharmer
type Sharding (line 9) | module Sharding
type Method (line 10) | module Method
class DbBlockGroupMap (line 11) | class DbBlockGroupMap
class Shard (line 13) | class Shard < ::ActiveRecord::Base
class Group (line 24) | class Group < ::ActiveRecord::Base
method initialize (line 48) | def initialize(config)
method shard_for_key (line 66) | def shard_for_key(key)
method block_for_key (line 83) | def block_for_key(key, cache = true)
method get_cached_block (line 105) | def get_cached_block(block_cache_key)
method set_cached_block (line 109) | def set_cached_block(block_cache_key, block)
method group_info_by_id (line 115) | def group_info_by_id(group_id, cache = true)
method shard_info_by_id (line 127) | def shard_info_by_id(shard_id, cache = true)
method shard_info_by_group_id (line 139) | def shard_info_by_group_id(group_id)
method allocate_new_block_for_key (line 151) | def allocate_new_block_for_key(key)
method least_loaded_group (line 178) | def least_loaded_group
method block_start_for_key (line 188) | def block_start_for_key(key)
method block_end_for_key (line 192) | def block_end_for_key(key)
method shard_connection_config (line 198) | def shard_connection_config(shard, group_id)
method group_database_name (line 217) | def group_database_name(shard, group_id)
method create_shard (line 222) | def create_shard(params)
method shard_connections (line 241) | def shard_connections
method prepare_shard_models (line 250) | def prepare_shard_models
FILE: lib/db_charmer/sharding/method/db_block_map.rb
type DbCharmer (line 5) | module DbCharmer
type Sharding (line 6) | module Sharding
type Method (line 7) | module Method
class DbBlockMap (line 8) | class DbBlockMap
method initialize (line 24) | def initialize(config)
method shard_for_key (line 39) | def shard_for_key(key)
class ShardInfo (line 61) | class ShardInfo < ::ActiveRecord::Base
method block_for_key (line 70) | def block_for_key(key, cache = true)
method get_cached_block (line 91) | def get_cached_block(block_cache_key)
method set_cached_block (line 95) | def set_cached_block(block_cache_key, block)
method shard_info_by_id (line 100) | def shard_info_by_id(shard_id, cache = true)
method allocate_new_block_for_key (line 111) | def allocate_new_block_for_key(key)
method least_loaded_shard (line 138) | def least_loaded_shard
method block_start_for_key (line 147) | def block_start_for_key(key)
method block_end_for_key (line 151) | def block_end_for_key(key)
method shard_connection_config (line 156) | def shard_connection_config(shard)
method create_shard (line 175) | def create_shard(params)
method shard_connections (line 194) | def shard_connections
method prepare_shard_model (line 203) | def prepare_shard_model
FILE: lib/db_charmer/sharding/method/hash_map.rb
type DbCharmer (line 1) | module DbCharmer
type Sharding (line 2) | module Sharding
type Method (line 3) | module Method
class HashMap (line 4) | class HashMap
method initialize (line 7) | def initialize(config)
method shard_for_key (line 11) | def shard_for_key(key)
method support_default_shard? (line 17) | def support_default_shard?
FILE: lib/db_charmer/sharding/method/range.rb
type DbCharmer (line 1) | module DbCharmer
type Sharding (line 2) | module Sharding
type Method (line 3) | module Method
class Range (line 4) | class Range
method initialize (line 7) | def initialize(config)
method shard_for_key (line 11) | def shard_for_key(key)
method support_default_shard? (line 23) | def support_default_shard?
method shard_connections (line 27) | def shard_connections
FILE: lib/db_charmer/sharding/stub_connection.rb
type DbCharmer (line 7) | module DbCharmer
type Sharding (line 8) | module Sharding
class StubConnection (line 9) | class StubConnection
method initialize (line 12) | def initialize(sharded_connection)
method set_real_connection (line 17) | def set_real_connection(real_conn)
method db_charmer_connection_name (line 21) | def db_charmer_connection_name
method real_connection (line 25) | def real_connection
method respond_to? (line 40) | def respond_to?(method_name, include_all = false)
method method_missing (line 46) | def method_missing(meth, *args, &block)
FILE: lib/db_charmer/tasks/databases.rake
function create_core_and_sub_database (line 29) | def create_core_and_sub_database(config)
function local_database? (line 61) | def local_database?(config, &block)
function drop_core_and_sub_database (line 70) | def drop_core_and_sub_database(config)
FILE: lib/db_charmer/version.rb
type DbCharmer (line 1) | module DbCharmer
type Version (line 2) | module Version
FILE: lib/db_charmer/with_remapped_databases.rb
type DbCharmer (line 1) | module DbCharmer
function with_remapped_databases (line 2) | def self.with_remapped_databases(mappings, &proc)
function hijack_new_classes? (line 16) | def self.hijack_new_classes?
function with_all_hijacked (line 22) | def self.with_all_hijacked
class ActiveRecord::Base (line 39) | class ActiveRecord::Base
method inherited_with_hijacking (line 41) | def inherited_with_hijacking(subclass)
FILE: test-project-2.x/config/boot.rb
type Rails (line 9) | module Rails
function boot! (line 11) | def boot!
function booted? (line 18) | def booted?
function pick_boot (line 22) | def pick_boot
function vendor_rails? (line 26) | def vendor_rails?
function preinitialize (line 30) | def preinitialize
function preinitializer_path (line 34) | def preinitializer_path
class Boot (line 39) | class Boot
method run (line 40) | def run
class VendorBoot (line 53) | class VendorBoot < Boot
method load_initializer (line 54) | def load_initializer
class GemBoot (line 61) | class GemBoot < Boot
method load_initializer (line 62) | def load_initializer
method load_rails_gem (line 68) | def load_rails_gem
method rubygems_version (line 80) | def rubygems_version
method gem_version (line 84) | def gem_version
method load_rubygems (line 94) | def load_rubygems
method parse_gem_version (line 107) | def parse_gem_version(text)
method read_environment_rb (line 112) | def read_environment_rb
FILE: test-project/app/controllers/application_controller.rb
class ApplicationController (line 1) | class ApplicationController < ActionController::Base
FILE: test-project/app/controllers/posts_controller.rb
class PostsController (line 1) | class PostsController < ApplicationController
method index (line 9) | def index
method show (line 13) | def show
method new (line 17) | def new
method create (line 21) | def create
method destroy (line 26) | def destroy
FILE: test-project/app/helpers/application_helper.rb
type ApplicationHelper (line 1) | module ApplicationHelper
FILE: test-project/app/models/avatar.rb
class Avatar (line 1) | class Avatar < ActiveRecord::Base
FILE: test-project/app/models/car.rb
class Car (line 1) | class Car < ActiveRecord::Base
FILE: test-project/app/models/categories_posts.rb
class CategoriesPosts (line 1) | class CategoriesPosts < ActiveRecord::Base
FILE: test-project/app/models/category.rb
class Category (line 1) | class Category < ActiveRecord::Base
FILE: test-project/app/models/comment.rb
class Comment (line 1) | class Comment < ActiveRecord::Base
FILE: test-project/app/models/event.rb
class Event (line 1) | class Event < ActiveRecord::Base
FILE: test-project/app/models/ford.rb
class Ford (line 1) | class Ford < Car
FILE: test-project/app/models/house.rb
class House (line 1) | class House < ActiveRecord::Base
FILE: test-project/app/models/log_record.rb
class LogRecord (line 1) | class LogRecord < ActiveRecord::Base
FILE: test-project/app/models/post.rb
class Post (line 1) | class Post < ActiveRecord::Base
method define_scope (line 8) | def self.define_scope(*args, &block)
FILE: test-project/app/models/range_sharded_model.rb
class RangeShardedModel (line 1) | class RangeShardedModel < ActiveRecord::Base
FILE: test-project/app/models/toyota.rb
class Toyota (line 1) | class Toyota < Car
FILE: test-project/app/models/user.rb
class User (line 1) | class User < ActiveRecord::Base
FILE: test-project/config/application.rb
type DbCharmerSandbox (line 9) | module DbCharmerSandbox
class Application (line 10) | class Application < Rails::Application
FILE: test-project/db/migrate/20090810013829_create_log_records.rb
class CreateLogRecords (line 1) | class CreateLogRecords < ActiveRecord::Migration
method up (line 4) | def self.up
method down (line 13) | def self.down
FILE: test-project/db/migrate/20090810013922_create_posts.rb
class CreatePosts (line 1) | class CreatePosts < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 11) | def self.down
FILE: test-project/db/migrate/20090810221944_create_users.rb
class CreateUsers (line 1) | class CreateUsers < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 10) | def self.down
FILE: test-project/db/migrate/20100305234245_create_categories.rb
class CreateCategories (line 1) | class CreateCategories < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 10) | def self.down
FILE: test-project/db/migrate/20100305234340_create_categories_posts.rb
class CreateCategoriesPosts (line 1) | class CreateCategoriesPosts < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 10) | def self.down
FILE: test-project/db/migrate/20100305235831_create_avatars.rb
class CreateAvatars (line 1) | class CreateAvatars < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 11) | def self.down
FILE: test-project/db/migrate/20100328201317_create_sharding_map_tables.rb
class CreateShardingMapTables (line 1) | class CreateShardingMapTables < ActiveRecord::Migration
method up (line 4) | def self.up
method down (line 31) | def self.down
FILE: test-project/db/migrate/20100330180517_create_event_tables.rb
class CreateEventTables (line 1) | class CreateEventTables < ActiveRecord::Migration
method up (line 9) | def self.up
method down (line 30) | def self.down
FILE: test-project/db/migrate/20100817191548_create_cars.rb
class CreateCars (line 1) | class CreateCars < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 10) | def self.down
FILE: test-project/db/migrate/20111005193941_create_comments.rb
class CreateComments (line 1) | class CreateComments < ActiveRecord::Migration
method up (line 2) | def self.up
method down (line 12) | def self.down
FILE: test-project/db/sharding.sql
type `events_shard_info` (line 25) | CREATE TABLE `events_shard_info` (
type `events_shard_dict` (line 56) | CREATE TABLE `events_shard_dict` (
FILE: test-project/spec/integration/multi_threading_spec.rb
function do_test (line 4) | def do_test(test_seconds, thread_count)
class TestLogRecordWithThreads (line 31) | class TestLogRecordWithThreads < ActiveRecord::Base
class TestLogRecordWithThreadsAndRemapping (line 46) | class TestLogRecordWithThreadsAndRemapping < ActiveRecord::Base
FILE: test-project/spec/support/rails31_stub_connection.rb
function stub_columns_for_rails31 (line 1) | def stub_columns_for_rails31(connection)
FILE: test-project/spec/unit/action_controller/force_slave_reads_spec.rb
class BlahController (line 3) | class BlahController < ActionController::Base; end
FILE: test-project/spec/unit/active_record/class_attributes_spec.rb
class FooModel (line 3) | class FooModel < ActiveRecord::Base; end
FILE: test-project/spec/unit/active_record/connection_switching_spec.rb
class FooModelForConnSwitching (line 3) | class FooModelForConnSwitching < ActiveRecord::Base; end
class BarModelForConnSwitching (line 4) | class BarModelForConnSwitching < ActiveRecord::Base; end
FILE: test-project/spec/unit/active_record/db_magic_spec.rb
class Blah (line 3) | class Blah < ActiveRecord::Base; end
class ParentFoo (line 62) | class ParentFoo < ActiveRecord::Base
class ChildFoo (line 65) | class ChildFoo < ParentFoo; end
class ShardTestingFoo (line 71) | class ShardTestingFoo < ActiveRecord::Base
FILE: test-project/spec/unit/active_record/master_slave_routing_spec.rb
class User (line 5) | class User < ActiveRecord::Base
FILE: test-project/spec/unit/active_record/migration/multi_db_migrations_spec.rb
class SpecMigration (line 3) | class SpecMigration < ActiveRecord::Migration
method up (line 4) | def self.up
method down (line 8) | def self.down
class SpecMultiDbMigration (line 13) | class SpecMultiDbMigration < ActiveRecord::Migration
method up (line 16) | def self.up
method down (line 20) | def self.down
class SpecMultiDbMigration2 (line 25) | class SpecMultiDbMigration2 < ActiveRecord::Migration
method up (line 26) | def self.up
method down (line 31) | def self.down
class SpecMultiDbMigration3 (line 37) | class SpecMultiDbMigration3 < ActiveRecord::Migration
method up (line 40) | def self.up
method down (line 44) | def self.down
class SpecMultiDbMigration4 (line 49) | class SpecMultiDbMigration4 < ActiveRecord::Migration
method up (line 52) | def self.up
method down (line 56) | def self.down
class SpecMultiDbMigration5 (line 61) | class SpecMultiDbMigration5 < ActiveRecord::Migration
method up (line 64) | def up
method down (line 68) | def down
class SpecMultiDbMigration6 (line 73) | class SpecMultiDbMigration6 < ActiveRecord::Migration
method change (line 74) | def change
function connection_with_name (line 92) | def connection_with_name(name)
FILE: test-project/spec/unit/active_record/relation_spec.rb
class RelTestModel (line 6) | class RelTestModel < ActiveRecord::Base
FILE: test-project/spec/unit/connection_proxy_spec.rb
class ProxyTest (line 5) | class ProxyTest; end
type MockConnection (line 21) | module MockConnection
function foo (line 22) | def self.foo
FILE: test-project/spec/unit/multi_db_proxy_spec.rb
class Blah (line 5) | class Blah < ActiveRecord::Base
FILE: test-project/spec/unit/with_remapped_databases_spec.rb
class User (line 13) | class User < ActiveRecord::Base
function should_have_connection (line 18) | def should_have_connection(model_class, connection)
function unhijack! (line 94) | def unhijack!(klass)
Condensed preview — 160 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (330K chars).
[
{
"path": ".gitignore",
"chars": 31,
"preview": "doc\npkg\n.DS_Store\n_site\n.idea\n\n"
},
{
"path": ".travis.yml",
"chars": 894,
"preview": "language: ruby\nrvm:\n - 1.8.7\n - 1.9.3\n - 2.0.0\n\nenv:\n - RAILS_VERSION=2.x\n - RAILS_VERSION=3.0.20\n - RAILS_VERSION"
},
{
"path": "CHANGES",
"chars": 10649,
"preview": "1.9.1 (2014-11-14):\n\nThe project has been suspended. No updates will be provided and no Rails versions\nbeyond 3.2.x will"
},
{
"path": "LICENSE",
"chars": 1077,
"preview": "The MIT License\n\nCopyright (c) 2011, Oleksiy Kovyrin\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "Makefile",
"chars": 57,
"preview": "doc/files/README_rdoc.html:\tREADME.rdoc\n\trdoc README.rdoc"
},
{
"path": "README.rdoc",
"chars": 4630,
"preview": "= WARNING: The Project Has Been Suspended\n\nPlease note, that this project has been suspended. No updates will be provide"
},
{
"path": "Rakefile",
"chars": 67,
"preview": "require 'rake'\nrequire 'bundler'\n\nBundler::GemHelper.install_tasks\n"
},
{
"path": "ci_build",
"chars": 1517,
"preview": "#!/bin/bash\n\n# Making the script more robust\nset -e # Exit on errors\nset -u # Exit on uninitialized variables\n\nRAILS_VER"
},
{
"path": "db-charmer.gemspec",
"chars": 1195,
"preview": "# -*- encoding: utf-8 -*-\n$:.push File.expand_path('../lib', __FILE__)\nrequire 'db_charmer/version'\n\nGem::Specification."
},
{
"path": "init.rb",
"chars": 21,
"preview": "require 'db_charmer'\n"
},
{
"path": "issues/issues-as-of-2014-11-14.json",
"chars": 91576,
"preview": "[\n {\n \"url\": \"https://api.github.com/repos/kovyrin/db-charmer/issues/98\",\n \"labels_url\": \"https://api.github.com/"
},
{
"path": "lib/db_charmer/action_controller/force_slave_reads.rb",
"chars": 2198,
"preview": "module DbCharmer\n module ActionController\n module ForceSlaveReads\n\n module ClassMethods\n @@db_charmer_fo"
},
{
"path": "lib/db_charmer/active_record/association_preload.rb",
"chars": 881,
"preview": "module DbCharmer\n module ActiveRecord\n module AssociationPreload\n ASSOCIATION_TYPES = [ :has_one, :has_many, :b"
},
{
"path": "lib/db_charmer/active_record/class_attributes.rb",
"chars": 4075,
"preview": "module DbCharmer\n module ActiveRecord\n module ClassAttributes\n @@db_charmer_opts = {}\n def db_charmer_opts"
},
{
"path": "lib/db_charmer/active_record/connection_switching.rb",
"chars": 3891,
"preview": "module DbCharmer\n module ActiveRecord\n module ConnectionSwitching\n def establish_real_connection_if_exists(name"
},
{
"path": "lib/db_charmer/active_record/db_magic.rb",
"chars": 3218,
"preview": "module DbCharmer\n module ActiveRecord\n module DbMagic\n\n def db_magic(opt = {})\n # Make sure we could use"
},
{
"path": "lib/db_charmer/active_record/migration/multi_db_migrations.rb",
"chars": 4719,
"preview": "module DbCharmer\n module ActiveRecord\n module Migration\n module MultiDbMigrations\n\n def self.append_feat"
},
{
"path": "lib/db_charmer/active_record/multi_db_proxy.rb",
"chars": 2561,
"preview": "module DbCharmer\n module ActiveRecord\n module MultiDbProxy\n # Simple proxy class that switches connections and "
},
{
"path": "lib/db_charmer/active_record/sharding.rb",
"chars": 1304,
"preview": "module DbCharmer\n module ActiveRecord\n module Sharding\n\n def self.extended(model)\n model.cattr_accessor("
},
{
"path": "lib/db_charmer/connection_factory.rb",
"chars": 3284,
"preview": "#\n# This class is used to automatically generate small abstract ActiveRecord classes\n# that would then be used as a sour"
},
{
"path": "lib/db_charmer/connection_proxy.rb",
"chars": 1775,
"preview": "# Simple proxy that sends all method calls to a real database connection\nmodule DbCharmer\n class ConnectionProxy < Acti"
},
{
"path": "lib/db_charmer/core_extensions.rb",
"chars": 405,
"preview": "class Object\n unless defined?(try)\n def try(method, *options, &block)\n send(method, *options, &block)\n end\n "
},
{
"path": "lib/db_charmer/force_slave_reads.rb",
"chars": 2008,
"preview": "module DbCharmer\n def self.current_controller\n Thread.current[:db_charmer_current_controller]\n end\n\n def self.curr"
},
{
"path": "lib/db_charmer/rails2/abstract_adapter/log_formatting.rb",
"chars": 688,
"preview": "module DbCharmer\n module AbstractAdapter\n module LogFormatting\n\n def self.included(base)\n base.alias_met"
},
{
"path": "lib/db_charmer/rails2/active_record/master_slave_routing.rb",
"chars": 1270,
"preview": "module DbCharmer\n module ActiveRecord\n module MasterSlaveRouting\n\n module ClassMethods\n SLAVE_METHODS = "
},
{
"path": "lib/db_charmer/rails2/active_record/named_scope/scope_proxy.rb",
"chars": 504,
"preview": "module DbCharmer\n module ActiveRecord\n module NamedScope\n module ScopeProxy\n\n def proxy?\n true\n"
},
{
"path": "lib/db_charmer/rails3/abstract_adapter/connection_name.rb",
"chars": 1122,
"preview": "module DbCharmer\n module AbstractAdapter\n module ConnectionName\n\n # We use this proxy to push connection name d"
},
{
"path": "lib/db_charmer/rails3/active_record/log_subscriber.rb",
"chars": 662,
"preview": "module DbCharmer\n module ActiveRecord\n module LogSubscriber\n\n def self.included(base)\n base.send(:attr_a"
},
{
"path": "lib/db_charmer/rails3/active_record/master_slave_routing.rb",
"chars": 1220,
"preview": "module DbCharmer\n module ActiveRecord\n module MasterSlaveRouting\n\n module ClassMethods\n SLAVE_METHODS = "
},
{
"path": "lib/db_charmer/rails3/active_record/relation/connection_routing.rb",
"chars": 5527,
"preview": "module DbCharmer\n module ActiveRecord\n module Relation\n module ConnectionRouting\n\n # All the methods tha"
},
{
"path": "lib/db_charmer/rails3/active_record/relation_method.rb",
"chars": 822,
"preview": "module DbCharmer\n module ActiveRecord\n module RelationMethod\n\n def self.extended(base)\n class << base\n "
},
{
"path": "lib/db_charmer/rails31/active_record/migration/command_recorder.rb",
"chars": 225,
"preview": "module DbCharmer\n module ActiveRecord\n module Migration\n module CommandRecorder\n def invert_on_db(args)\n"
},
{
"path": "lib/db_charmer/rails31/active_record/preloader/association.rb",
"chars": 591,
"preview": "module DbCharmer\n module ActiveRecord\n module Preloader\n module Association\n extend ActiveSupport::Conce"
},
{
"path": "lib/db_charmer/rails31/active_record/preloader/has_and_belongs_to_many.rb",
"chars": 653,
"preview": "module DbCharmer\n module ActiveRecord\n module Preloader\n module HasAndBelongsToMany\n extend ActiveSuppor"
},
{
"path": "lib/db_charmer/railtie.rb",
"chars": 133,
"preview": "module DbCharmer\n class Railtie < Rails::Railtie\n\n rake_tasks do\n load \"db_charmer/tasks/databases.rake\"\n en"
},
{
"path": "lib/db_charmer/sharding/connection.rb",
"chars": 887,
"preview": "module DbCharmer\n module Sharding\n class Connection\n attr_accessor :config, :sharder\n\n def initialize(conf"
},
{
"path": "lib/db_charmer/sharding/method/db_block_group_map.rb",
"chars": 10025,
"preview": "# This is a more sophisticated sharding method based on a two layer database-backed\n# blocks map that holds block-shard "
},
{
"path": "lib/db_charmer/sharding/method/db_block_map.rb",
"chars": 7260,
"preview": "# This is a more sophisticated sharding method based on a database-backed\n# blocks map that holds block-shard associatio"
},
{
"path": "lib/db_charmer/sharding/method/hash_map.rb",
"chars": 532,
"preview": "module DbCharmer\n module Sharding\n module Method\n class HashMap\n attr_accessor :map\n\n def initial"
},
{
"path": "lib/db_charmer/sharding/method/range.rb",
"chars": 814,
"preview": "module DbCharmer\n module Sharding\n module Method\n class Range\n attr_accessor :ranges\n\n def initia"
},
{
"path": "lib/db_charmer/sharding/method.rb",
"chars": 342,
"preview": "module DbCharmer\n module Sharding\n module Method\n autoload :Range, 'db_charmer/sharding/method/range'\n aut"
},
{
"path": "lib/db_charmer/sharding/stub_connection.rb",
"chars": 2471,
"preview": "# This is a simple proxy class used as a default connection on sharded models\n#\n# The idea is to proxy all utility metho"
},
{
"path": "lib/db_charmer/sharding.rb",
"chars": 602,
"preview": "module DbCharmer\n module Sharding\n autoload :Connection, 'db_charmer/sharding/connection'\n autoload :StubConnecti"
},
{
"path": "lib/db_charmer/tasks/databases.rake",
"chars": 2582,
"preview": "namespace :db_charmer do\n namespace :create do\n desc 'Create all the local databases defined in config/database.yml'"
},
{
"path": "lib/db_charmer/version.rb",
"chars": 163,
"preview": "module DbCharmer\n module Version\n MAJOR = 1\n MINOR = 9\n PATCH = 1\n BUILD = nil\n\n STRING = [MAJOR, MINOR,"
},
{
"path": "lib/db_charmer/with_remapped_databases.rb",
"chars": 1489,
"preview": "module DbCharmer\n def self.with_remapped_databases(mappings, &proc)\n old_mappings = ::ActiveRecord::Base.db_charmer_"
},
{
"path": "lib/db_charmer.rb",
"chars": 8676,
"preview": "# In Rails 2.2 they did not add it to the autoload so it won't work w/o this require\nrequire 'active_record/version' unl"
},
{
"path": "test-project/.gitignore",
"chars": 99,
"preview": "log/*.log\ndb/schema.*\n.idea\nTAGS\nconfig/database.yml\n.bundle\ntmp\n.DS_Store\nvendor\nGemfile.lock\ndoc\n"
},
{
"path": "test-project/.rspec",
"chars": 32,
"preview": "--colour\n--format documentation\n"
},
{
"path": "test-project/Gemfile",
"chars": 1451,
"preview": "source 'http://rubygems.org'\n\ngem 'rake', \"0.9.2.2\"\ngem 'mysql', \"2.8.1\"\n\ngem 'rspec', '< 3.0'\ngem 'rspec-core', '< 3.0'"
},
{
"path": "test-project/Rakefile",
"chars": 303,
"preview": "ENV['RAILS_ENV'] = 'test'\n\n# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/ca"
},
{
"path": "test-project/TODO",
"chars": 284,
"preview": "Functionality:\n- Add a controller wrapper to force all queries to the master (thanks mascohism for the idea)\n\nDocs:\n- Do"
},
{
"path": "test-project/app/controllers/application_controller.rb",
"chars": 80,
"preview": "class ApplicationController < ActionController::Base\n protect_from_forgery\nend\n"
},
{
"path": "test-project/app/controllers/posts_controller.rb",
"chars": 546,
"preview": "class PostsController < ApplicationController\n force_slave_reads :only => [ :index, :show, :new ], :except => :new\n\n #"
},
{
"path": "test-project/app/helpers/application_helper.rb",
"chars": 29,
"preview": "module ApplicationHelper\nend\n"
},
{
"path": "test-project/app/models/avatar.rb",
"chars": 38,
"preview": "class Avatar < ActiveRecord::Base\nend\n"
},
{
"path": "test-project/app/models/car.rb",
"chars": 65,
"preview": "class Car < ActiveRecord::Base\n db_magic :slave => :slave01\nend\n"
},
{
"path": "test-project/app/models/categories_posts.rb",
"chars": 89,
"preview": "class CategoriesPosts < ActiveRecord::Base\n belongs_to :category\n belongs_to :post\nend\n"
},
{
"path": "test-project/app/models/category.rb",
"chars": 73,
"preview": "class Category < ActiveRecord::Base\n has_and_belongs_to_many :posts\nend\n"
},
{
"path": "test-project/app/models/comment.rb",
"chars": 87,
"preview": "class Comment < ActiveRecord::Base\n belongs_to :commentable, :polymorphic => true\nend\n"
},
{
"path": "test-project/app/models/event.rb",
"chars": 160,
"preview": "class Event < ActiveRecord::Base\n self.table_name = :timeline_events\n\n db_magic :sharded => {\n :key => :to_uid,\n "
},
{
"path": "test-project/app/models/ford.rb",
"chars": 20,
"preview": "class Ford < Car\nend"
},
{
"path": "test-project/app/models/house.rb",
"chars": 96,
"preview": "class House < ActiveRecord::Base\n db_magic :slave => :slave01, :force_slave_reads => false\nend\n"
},
{
"path": "test-project/app/models/log_record.rb",
"chars": 92,
"preview": "class LogRecord < ActiveRecord::Base\n db_magic :connection => :logs\n belongs_to :user\nend\n"
},
{
"path": "test-project/app/models/post.rb",
"chars": 473,
"preview": "class Post < ActiveRecord::Base\n DB_MAGIC_DEFAULT_PARAMS = { :slave => :slave01, :force_slave_reads => false }\n db_mag"
},
{
"path": "test-project/app/models/range_sharded_model.rb",
"chars": 130,
"preview": "class RangeShardedModel < ActiveRecord::Base\n db_magic :sharded => {\n :key => :id,\n :sharded_connection => :texts"
},
{
"path": "test-project/app/models/toyota.rb",
"chars": 22,
"preview": "class Toyota < Car\nend"
},
{
"path": "test-project/app/models/user.rb",
"chars": 96,
"preview": "class User < ActiveRecord::Base\n has_many :posts\n has_many :log_records\n has_one :avatar\nend\n"
},
{
"path": "test-project/app/views/layouts/application.html.erb",
"chars": 209,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <title>DbCharmerSandbox</title>\n <%= stylesheet_link_tag :all %>\n <%= javascript_inclu"
},
{
"path": "test-project/app/views/posts/index.html.erb",
"chars": 137,
"preview": "<h1>Posts</h1>\n<br/>\n<% @posts.each do |post| %>\n <p>\n Post #<%= post.id %><br/>\n <pre><%= post.inspect %></pre>\n"
},
{
"path": "test-project/app/views/posts/new.html.erb",
"chars": 66,
"preview": "<h1>Posts#new</h1>\n<p>Find me in app/views/posts/new.html.erb</p>\n"
},
{
"path": "test-project/app/views/posts/show.html.erb",
"chars": 68,
"preview": "<h1>Posts#show</h1>\n<p>Find me in app/views/posts/show.html.erb</p>\n"
},
{
"path": "test-project/config/application.rb",
"chars": 1934,
"preview": "require File.expand_path('../boot', __FILE__)\n\nrequire 'rails/all'\n\n# If you have a Gemfile, require the gems listed the"
},
{
"path": "test-project/config/boot.rb",
"chars": 191,
"preview": "require 'rubygems'\n\n# Set up gems listed in the Gemfile.\nENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __F"
},
{
"path": "test-project/config/database.yml.example",
"chars": 1503,
"preview": "common: &common\n adapter: mysql\n encoding: utf8\n reconnect: false\n pool: 10\n username: root\n password:\n\n#---------"
},
{
"path": "test-project/config/environment.rb",
"chars": 160,
"preview": "# Load the rails application\nrequire File.expand_path('../application', __FILE__)\n\n# Initialize the rails application\nDb"
},
{
"path": "test-project/config/environments/test.rb",
"chars": 1520,
"preview": "DbCharmerSandbox::Application.configure do\n # Settings specified here will take precedence over those in config/applica"
},
{
"path": "test-project/config/initializers/backtrace_silencers.rb",
"chars": 404,
"preview": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're"
},
{
"path": "test-project/config/initializers/db_charmer.rb",
"chars": 111,
"preview": "DbCharmer.connections_should_exist = false # Since we are not in production\nDbCharmer.enable_controller_magic!\n"
},
{
"path": "test-project/config/initializers/secret_token.rb",
"chars": 507,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key for verifying the integrity of signed coo"
},
{
"path": "test-project/config/initializers/session_store.rb",
"chars": 445,
"preview": "# Be sure to restart your server when you modify this file.\n\nDbCharmerSandbox::Application.config.session_store :cookie_"
},
{
"path": "test-project/config/initializers/sharding.rb",
"chars": 581,
"preview": "# Range-based shards for testing\n\nTEXTS_SHARDING_RANGES = {\n 0...100 => :shard1,\n 100..200 => :shard2,\n :default "
},
{
"path": "test-project/config/locales/en.yml",
"chars": 213,
"preview": "# Sample localization file for English. Add more files in this directory for other locales.\n# See http://github.com/sven"
},
{
"path": "test-project/config/routes.rb",
"chars": 1855,
"preview": "DbCharmerSandbox::Application.routes.draw do\n # The priority is based upon order of creation:\n # first created -> high"
},
{
"path": "test-project/db/create_databases.sql",
"chars": 468,
"preview": "drop database if exists db_charmer_sandbox_test;\ncreate database db_charmer_sandbox_test;\n\ndrop database if exists db_ch"
},
{
"path": "test-project/db/migrate/20090810013829_create_log_records.rb",
"chars": 292,
"preview": "class CreateLogRecords < ActiveRecord::Migration\n db_magic :connection => :logs\n\n def self.up\n create_table :log_re"
},
{
"path": "test-project/db/migrate/20090810013922_create_posts.rb",
"chars": 237,
"preview": "class CreatePosts < ActiveRecord::Migration\n def self.up\n create_table :posts do |t|\n t.string :title\n t.t"
},
{
"path": "test-project/db/migrate/20090810221944_create_users.rb",
"chars": 218,
"preview": "class CreateUsers < ActiveRecord::Migration\n def self.up\n create_table :users do |t|\n t.string :login\n t.s"
},
{
"path": "test-project/db/migrate/20100305234245_create_categories.rb",
"chars": 208,
"preview": "class CreateCategories < ActiveRecord::Migration\n def self.up\n create_table :categories do |t|\n t.string :name\n"
},
{
"path": "test-project/db/migrate/20100305234340_create_categories_posts.rb",
"chars": 305,
"preview": "class CreateCategoriesPosts < ActiveRecord::Migration\n def self.up\n pk_in_join_table = !DbCharmer.rails3?\n create"
},
{
"path": "test-project/db/migrate/20100305235831_create_avatars.rb",
"chars": 224,
"preview": "class CreateAvatars < ActiveRecord::Migration\n def self.up\n create_table :avatars do |t|\n t.integer :user_id\n "
},
{
"path": "test-project/db/migrate/20100328201317_create_sharding_map_tables.rb",
"chars": 1223,
"preview": "class CreateShardingMapTables < ActiveRecord::Migration\n db_magic :connection => :social_shard_info\n\n def self.up\n "
},
{
"path": "test-project/db/migrate/20100330180517_create_event_tables.rb",
"chars": 1128,
"preview": "class CreateEventTables < ActiveRecord::Migration\n # In test environment just use database.yml-defined connections\n if"
},
{
"path": "test-project/db/migrate/20100817191548_create_cars.rb",
"chars": 213,
"preview": "class CreateCars < ActiveRecord::Migration\n def self.up\n create_table :cars do |t|\n t.string :type\n t.stri"
},
{
"path": "test-project/db/migrate/20111005193941_create_comments.rb",
"chars": 331,
"preview": "class CreateComments < ActiveRecord::Migration\n def self.up\n create_table :comments do |t|\n t.string :commenta"
},
{
"path": "test-project/db/seeds.rb",
"chars": 353,
"preview": "# This file should contain all the record creation needed to seed the database with its default values.\n# The data can t"
},
{
"path": "test-project/db/sharding.sql",
"chars": 3254,
"preview": "-- MySQL dump 10.13 Distrib 5.1.44, for apple-darwin10.2.0 (i386)\n--\n-- Host: localhost Database: db_charmer_sandbox"
},
{
"path": "test-project/spec/controllers/posts_controller_spec.rb",
"chars": 3450,
"preview": "require 'spec_helper'\n\ndescribe PostsController do\n fixtures :posts\n\n # Delete these examples and add some real ones\n "
},
{
"path": "test-project/spec/fixtures/avatars.yml",
"chars": 143,
"preview": "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\n\none:\n user_id: 1\n name: avatar1\n\ntwo:\n user"
},
{
"path": "test-project/spec/fixtures/categories.yml",
"chars": 125,
"preview": "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\n\none:\n id: 1\n name: one\n\ntwo:\n id: 2\n name:"
},
{
"path": "test-project/spec/fixtures/categories_posts.yml",
"chars": 237,
"preview": "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\n\none_one:\n post_id: 1\n category_id: 1\n\none_tw"
},
{
"path": "test-project/spec/fixtures/comments.yml",
"chars": 180,
"preview": "avatar:\n commentable: one (Avatar)\n body: \"This is an avatar\"\n\npost:\n commentable: one (Post)\n body: \"This is a post"
},
{
"path": "test-project/spec/fixtures/event_shards_info.yml",
"chars": 601,
"preview": "shard1:\n id: 1\n db_host: localhost\n db_name: db_charmer_events_test_shard01\n open: 1\n enabled: 1\n blocks_count: 2\n"
},
{
"path": "test-project/spec/fixtures/event_shards_map.yml",
"chars": 442,
"preview": "block1:\n start_id: 0\n end_id: 10\n shard_id: 1\n block_size: 10\n created_at: <%= Time.now.to_s(:db) %>\n updated_at: "
},
{
"path": "test-project/spec/fixtures/log_records.yml",
"chars": 161,
"preview": "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\n\none:\n level: MyString\n message: MyString\n\ntw"
},
{
"path": "test-project/spec/fixtures/posts.yml",
"chars": 253,
"preview": "one:\n id: 1\n title: MyString\n body: MyText\n user_id: 1\n\ntwo:\n id: 2\n title: MyString\n body: MyText\n user_id: 2\n\n"
},
{
"path": "test-project/spec/fixtures/users.yml",
"chars": 228,
"preview": "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\n\none:\n id: 1\n login: MyString\n password: MyS"
},
{
"path": "test-project/spec/integration/multi_threading_spec.rb",
"chars": 1908,
"preview": "require 'spec_helper'\n\ndescribe \"DbCharmer integration tests\" do\n def do_test(test_seconds, thread_count)\n start_tim"
},
{
"path": "test-project/spec/models/avatar_spec.rb",
"chars": 263,
"preview": "require 'spec_helper'\n\ndescribe Avatar do\n before(:each) do\n @valid_attributes = {\n :user_id => 1,\n :name "
},
{
"path": "test-project/spec/models/cars_spec.rb",
"chars": 658,
"preview": "require 'spec_helper'\n\ndescribe Ford, \"STI model\" do\n before(:each) do\n @valid_attributes = {\n :license => \"FFG"
},
{
"path": "test-project/spec/models/categories_posts_spec.rb",
"chars": 273,
"preview": "require 'spec_helper'\n\ndescribe CategoriesPosts do\n before(:each) do\n @valid_attributes = {\n :post_id => 1,\n "
},
{
"path": "test-project/spec/models/category_spec.rb",
"chars": 246,
"preview": "require 'spec_helper'\n\ndescribe Category do\n before(:each) do\n @valid_attributes = {\n :name => \"value for name\""
},
{
"path": "test-project/spec/models/comment_spec.rb",
"chars": 283,
"preview": "require 'spec_helper'\n\ndescribe Comment do\n fixtures :comments, :avatars, :posts, :users\n\n describe \"preload polymorph"
},
{
"path": "test-project/spec/models/event_spec.rb",
"chars": 2476,
"preview": "require 'spec_helper'\n\ndescribe Event, \"sharded model\" do\n fixtures :event_shards_info, :event_shards_map\n\n it \"should"
},
{
"path": "test-project/spec/models/log_record_spec.rb",
"chars": 289,
"preview": "require 'spec_helper'\n\ndescribe LogRecord do\n before(:each) do\n @valid_attributes = {\n :level => \"value for lev"
},
{
"path": "test-project/spec/models/post_spec.rb",
"chars": 273,
"preview": "require 'spec_helper'\n\ndescribe Post do\n before(:each) do\n @valid_attributes = {\n :title => \"value for title\",\n"
},
{
"path": "test-project/spec/models/range_sharded_model_spec.rb",
"chars": 1403,
"preview": "require 'spec_helper'\n\ndescribe RangeShardedModel do\n describe \"class method shard_for\" do\n describe \"should correct"
},
{
"path": "test-project/spec/models/user_spec.rb",
"chars": 820,
"preview": "require 'spec_helper'\n\ndescribe User do\n before(:each) do\n @valid_attributes = {\n :login => \"value for login\",\n"
},
{
"path": "test-project/spec/sharding/connection_spec.rb",
"chars": 871,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer::Sharding::Connection do\n describe \"in constructor\" do\n it \"should not fai"
},
{
"path": "test-project/spec/sharding/method/db_block_map_spec.rb",
"chars": 4519,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer::Sharding::Method::DbBlockMap do\n fixtures :event_shards_info, :event_shards_"
},
{
"path": "test-project/spec/sharding/method/hash_map_spec.rb",
"chars": 1199,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer::Sharding::Method::HashMap do\n SHARDING_MAP = {\n 'US' => :us_users,\n '"
},
{
"path": "test-project/spec/sharding/method/range_spec.rb",
"chars": 1438,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer::Sharding::Method::Range do\n SHARDING_RANGES = {\n 0...100 => :shard1,\n "
},
{
"path": "test-project/spec/sharding/sharding_spec.rb",
"chars": 829,
"preview": "require 'spec_helper'\n\ndescribe \"DbCharmer::Sharding\" do\n describe \"in register_connection method\" do\n it \"should ra"
},
{
"path": "test-project/spec/spec_helper.rb",
"chars": 1021,
"preview": "# This file is copied to spec/ when you run 'rails generate rspec:install'\nENV[\"RAILS_ENV\"] = 'test'\nrequire File.expand"
},
{
"path": "test-project/spec/support/rails31_stub_connection.rb",
"chars": 169,
"preview": "def stub_columns_for_rails31(connection)\n return unless DbCharmer.rails31?\n connection.abstract_connection_class.retri"
},
{
"path": "test-project/spec/unit/abstract_adapter/log_formatting_spec.rb",
"chars": 999,
"preview": "require 'spec_helper'\n\nif DbCharmer.rails2?\n describe 'AbstractAdapter' do\n it \"should respond to connection_name ac"
},
{
"path": "test-project/spec/unit/action_controller/force_slave_reads_spec.rb",
"chars": 1691,
"preview": "require 'spec_helper'\n\nclass BlahController < ActionController::Base; end\n\ndescribe ActionController, \"with force_slave_"
},
{
"path": "test-project/spec/unit/active_record/association_preload_spec.rb",
"chars": 1822,
"preview": "require 'spec_helper'\n\nif DbCharmer.rails2?\n describe \"ActiveRecord preload_associations method\" do\n it \"should be p"
},
{
"path": "test-project/spec/unit/active_record/association_proxy_spec.rb",
"chars": 2984,
"preview": "require 'spec_helper'\n\ndescribe \"DbCharmer::AssociationProxy extending AR::Associations\" do\n fixtures :users, :posts\n\n "
},
{
"path": "test-project/spec/unit/active_record/class_attributes_spec.rb",
"chars": 3984,
"preview": "require 'spec_helper'\n\nclass FooModel < ActiveRecord::Base; end\n\ndescribe DbCharmer, \"for ActiveRecord models\" do\n cont"
},
{
"path": "test-project/spec/unit/active_record/connection_switching_spec.rb",
"chars": 3892,
"preview": "require 'spec_helper'\n\nclass FooModelForConnSwitching < ActiveRecord::Base; end\nclass BarModelForConnSwitching < ActiveR"
},
{
"path": "test-project/spec/unit/active_record/db_magic_spec.rb",
"chars": 2848,
"preview": "require 'spec_helper'\n\nclass Blah < ActiveRecord::Base; end\n\ndescribe \"In ActiveRecord models\" do\n describe \"db_magic m"
},
{
"path": "test-project/spec/unit/active_record/master_slave_routing_spec.rb",
"chars": 4729,
"preview": "require 'spec_helper'\n\ndescribe \"ActiveRecord slave-enabled models\" do\n before do\n class User < ActiveRecord::Base\n "
},
{
"path": "test-project/spec/unit/active_record/migration/multi_db_migrations_spec.rb",
"chars": 7626,
"preview": "require 'spec_helper'\n\nclass SpecMigration < ActiveRecord::Migration\n def self.up\n execute \"UPDATE log_records SET l"
},
{
"path": "test-project/spec/unit/active_record/named_scope/named_scope_spec.rb",
"chars": 1871,
"preview": "require 'spec_helper'\n\ndescribe \"Named scopes\" do\n fixtures :users, :posts\n\n before(:all) do\n Post.switch_connectio"
},
{
"path": "test-project/spec/unit/active_record/relation_spec.rb",
"chars": 2489,
"preview": "require 'spec_helper'\n\nif DbCharmer.rails3?\n describe \"ActiveRecord::Relation for a model with db_magic\" do\n before "
},
{
"path": "test-project/spec/unit/connection_factory_spec.rb",
"chars": 4658,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer::ConnectionFactory do\n context \"in generate_abstract_class method\" do\n it "
},
{
"path": "test-project/spec/unit/connection_proxy_spec.rb",
"chars": 1006,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer::ConnectionProxy do\n before(:each) do\n class ProxyTest; end\n @conn = mo"
},
{
"path": "test-project/spec/unit/db_charmer_spec.rb",
"chars": 2877,
"preview": "require 'spec_helper'\n\ndescribe DbCharmer do\n after do\n DbCharmer.current_controller = nil\n DbCharmer.connections"
},
{
"path": "test-project/spec/unit/multi_db_proxy_spec.rb",
"chars": 4877,
"preview": "require 'spec_helper'\n\ndescribe \"ActiveRecord model with db_magic\" do\n before do\n class Blah < ActiveRecord::Base\n "
},
{
"path": "test-project/spec/unit/with_remapped_databases_spec.rb",
"chars": 4792,
"preview": "require 'spec_helper'\n\ndescribe \"DbCharmer#with_remapped_databases\" do\n before(:all) do\n DbCharmer.connections_shoul"
},
{
"path": "test-project-2.x/Gemfile",
"chars": 221,
"preview": "source 'http://rubygems.org'\n\ngem 'rails', '2.3.18'\n\ngem 'rake', '0.9.2.2'\ngem 'mysql'\n\ngem 'rspec', '1.3.2'\ngem 'rspec-"
},
{
"path": "test-project-2.x/Rakefile",
"chars": 307,
"preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
},
{
"path": "test-project-2.x/config/boot.rb",
"chars": 3010,
"preview": "# We only have test environment here\nENV['RAILS_ENV'] = 'test'\n\n# Don't change this file!\n# Configure your app in config"
},
{
"path": "test-project-2.x/config/database.yml.example",
"chars": 1502,
"preview": "common: &common\n adapter: mysql\n encoding: utf8\n reconnect: false\n pool: 1\n username: root\n password:\n\n#----------"
},
{
"path": "test-project-2.x/config/environment.rb",
"chars": 328,
"preview": "# Specifies gem version of Rails to use when vendor/rails is not present\nRAILS_GEM_VERSION = '2.3.18' unless defined? RA"
},
{
"path": "test-project-2.x/config/environments/test.rb",
"chars": 1312,
"preview": "# Settings specified here will take precedence over those in config/environment.rb\n\n# The test environment is used exclu"
},
{
"path": "test-project-2.x/config/initializers/backtrace_silencers.rb",
"chars": 404,
"preview": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're"
},
{
"path": "test-project-2.x/config/initializers/db_charmer.rb",
"chars": 110,
"preview": "DbCharmer.connections_should_exist = false # Since we are not in production\nDbCharmer.enable_controller_magic!"
},
{
"path": "test-project-2.x/config/initializers/inflections.rb",
"chars": 377,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format \n# (a"
},
{
"path": "test-project-2.x/config/initializers/mime_types.rb",
"chars": 205,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new mime types for use in respond_to blocks:\n# Mime::"
},
{
"path": "test-project-2.x/config/initializers/new_rails_defaults.rb",
"chars": 778,
"preview": "# Be sure to restart your server when you modify this file.\n\n# These settings change the behavior of Rails 2 apps and wi"
},
{
"path": "test-project-2.x/config/initializers/session_store.rb",
"chars": 811,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key for verifying cookie session data integri"
},
{
"path": "test-project-2.x/config/initializers/sharding.rb",
"chars": 581,
"preview": "# Range-based shards for testing\n\nTEXTS_SHARDING_RANGES = {\n 0...100 => :shard1,\n 100..200 => :shard2,\n :default "
},
{
"path": "test-project-2.x/config/locales/en.yml",
"chars": 212,
"preview": "# Sample localization file for English. Add more files in this directory for other locales.\n# See http://github.com/sven"
},
{
"path": "test-project-2.x/config/preinitializer.rb",
"chars": 601,
"preview": "begin\n require \"rubygems\"\n require \"bundler\"\nrescue LoadError\n raise \"Could not load the bundler gem. Install it with"
},
{
"path": "test-project-2.x/config/routes.rb",
"chars": 458,
"preview": "ActionController::Routing::Routes.draw do |map|\n # Resource routes\n map.resources :posts\n map.resources :cars\n\n # In"
},
{
"path": "test-project-2.x/script/console",
"chars": 98,
"preview": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/console'\n"
},
{
"path": "test-project-2.x/spec/spec.opts",
"chars": 26,
"preview": "--colour\n--format specdoc\n"
},
{
"path": "test-project-2.x/spec/spec_helper.rb",
"chars": 1833,
"preview": "# This file is copied to ~/spec when you run 'ruby script/generate rspec'\n# from the project root directory.\nENV[\"RAILS_"
}
]
About this extraction
This page contains the full source code of the kovyrin/db-charmer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 160 files (297.8 KB), approximately 84.1k tokens, and a symbol index with 437 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.