Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

dbslayer-adapter: some tweaks before release

git-svn-id: svn://newsprojects.nytimes.com/newsdev/gems/activerecord-dbslayer-adapter@4383 ae54da50-7589-804d-96e1-6ee4b2538e53
  • Loading branch information...
commit 0ad288887d167265431c0cbbdce8257bd403af88 1 parent 7a8935e
harrisj authored
6 History.txt
View
@@ -1,3 +1,9 @@
+== 0.0.2 2008-05-01
+
+* 2 major enhancments:
+ * tests
+ * it actually works!
+
== 0.0.1 2008-04-15
* 1 major enhancement:
1  Manifest.txt
View
@@ -7,6 +7,7 @@ config/hoe.rb
config/requirements.rb
lib/active_record/connection_adapters/dbslayer_adapter.rb
lib/active_record/connection_adapters/dbslayer_connection.rb
+lib/activerecord-dbslayer-adapter.rb
log/debug.log
script/console
script/destroy
46 README.txt
View
@@ -1,32 +1,64 @@
= activerecord_dbslayer_adapter
-* FIX (url)
+Jacob Harris
+jharris@nytimes.com
== DESCRIPTION:
-FIX (describe your package)
+An ActiveRecord adapter for using the DBSlayer proxy/pooling layer. This allows you to proxy and pool connections to the MySQL backend without worrying about scaling up the front instances more than MySQL is configured to handle (the dreaded Too Many Connections error). Of course, you can also reconfigure master/slave instances on the fly in DBSlayer without having to reconfigure or restart your Rails applications.
+
+This adapter is really just a judicious subclassing of functionality in the MySQL adapter, so the documented methods might seem very sparse (I only have to override what's changed). Mainly, I swapped it out to execute queries as JSON-over-HTTP calls to DBSlayer rather than using the MySQL connection library.
+
+== MAJOR CAVEATS:
+
+DBSlayer is a stateless pooling layer. This allows it to easily scale (why do you think HTTP is stateless?), but there are certain database techniques that will have to be abandoned or modified if you use it. The main problem is that each MySQL statement may execute on a different connection (and sometimes on different servers if you've set up transparent slave pooling), so you can not assume the context of one statement is available to the next.
+
+This becomes a problem with transactions. Although DBSlayer can support transactions if you use semicolons to include them all as one statement like
+ BEGIN TRANSACTION; more SQL; COMMIT TRANSACTION
+There is no readily apparent way to do that via ActiveRecord's block construction (all the adapter has are begin_transaction, commit_transaction methods). So for the moment, transactions do not throw errors but they don't actually use SQL transactions either. Sorry about that. In addition, disabling referential integrity for a connection is not allowed.
+
+The biggest problem is that Rails sets a connection variable for all MySQL connections in order to fix an error selecting null IDs (http://dev.rubyonrails.org/ticket/6778). Since DBSlayer is stateless, this fix doesn't work, but there unfortunately also doesn't seem to be a database or server setting you can alter instead. As a result, the following types of queries WILL return unexpected results when using the DBSlayer adapter:
+
+ Restaurant.find(:all, :conditions => 'id IS NULL')
+
+The problem only occurs when searching for null autoincrement primary key columns (not other columns). With the regular MySQL adapter, this would return records with an id value (normally errors). With the DBSlayer adapter, it returns the last inserted item into the table (this is the default MySQL behavior). Luckily, this is not a common idiom in Rails, but you should be aware if you attempt to use it for finding errors in your tables.
== FEATURES/PROBLEMS:
-* FIX (list of features or problems)
+* More tests
+* Better documentation
== SYNOPSIS:
- FIX (code sample of usage)
+In your databases.yml
+
+ production:
+ adapter: dbslayer
+ host: localhost
+ port: 9090
+
+All of the other normal database setting like the MySQL server, username, password, etc. are specified in the dbslayer daemon's configuration.
== REQUIREMENTS:
-* FIX (list of requirements)
+* the JSON gem
+* A running DBSlayer instance
== INSTALL:
-* FIX (sudo gem install, anything else)
+* gem install activerecord-dbslayer-adapter
+* in your rails project, add the following line at the end of config/environment.rb
+ Rails::Initializer.run do |config|
+ ...
+
+ require 'activerecord-dbslayer-adapter'
+ end
== LICENSE:
(The MIT License)
-Copyright (c) 2008 FIX
+Copyright (c) 2008
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
8 config/hoe.rb
View
@@ -1,10 +1,10 @@
-require 'active_record/connection_adapters/dbslayer_adapter'
+require 'activerecord-dbslayer-adapter'
AUTHOR = 'Jacob Harris' # can also be an array of Authors
EMAIL = "jharris@nytimes.com"
DESCRIPTION = "An ActiveRecord adapter to DBSlayer"
-GEM_NAME = 'activerecord_dbslayer_adapter' # what ppl will type to install your gem
-RUBYFORGE_PROJECT = 'activerecord_dbslayer_adapter' # The unix name for your project
+GEM_NAME = 'activerecord-dbslayer-adapter' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'activerecord-dbslayer-adapter' # The unix name for your project
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
@@ -32,7 +32,7 @@ def rubyforge_username
# UNCOMMENT IF REQUIRED:
# REV = YAML.load(`svn info`)['Revision']
VERS = ActiveRecord::ConnectionAdapters::DbslayerAdapter::VERSION + (REV ? ".#{REV}" : "")
-RDOC_OPTS = ['--quiet', '--title', 'activerecord_dbslayer_adapter documentation',
+RDOC_OPTS = ['--quiet', '--title', 'activerecord-dbslayer-adapter documentation',
"--opname", "index.html",
"--line-numbers",
"--main", "README",
33 lib/active_record/connection_adapters/dbslayer_adapter.rb
View
@@ -16,38 +16,15 @@ def self.dbslayer_connection(config) # :nodoc:
end
module ConnectionAdapters
+ ##
+ # This is just a basic inheritance of MysqlColumn
class DbslayerColumn < MysqlColumn #:nodoc:
- # def extract_default(default)
- # if type == :binary || type == :text
- # if default.blank?
- # default
- # else
- # raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
- # end
- # elsif missing_default_forged_as_empty_string?(default)
- # nil
- # else
- # super
- # end
- # end
-
private
- def simplified_type(field_type)
+ def simplified_type(field_type) #:nodoc:
return :boolean if DbslayerAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
return :string if field_type =~ /enum/i
super
end
-
- # MySQL misreports NOT NULL column default when none is given.
- # We can't detect this for columns which may have a legitimate ''
- # default (string) but we can for others (integer, datetime, boolean,
- # and the rest).
- #
- # Test whether the column has default '', is not null, and is not
- # a type allowing default ''.
- # def missing_default_forged_as_empty_string?(default)
- # type != :string && !null && default == ''
- # end
end
# The DbslayerAdapter is an adapter to use Rails with the DBSlayer
@@ -63,9 +40,9 @@ def simplified_type(field_type)
# to your environment.rb file:
#
# ActiveRecord::ConnectionAdapters::DbslayerAdapter.emulate_booleans = false
+ #
+ # MAJOR WARNING: The MySQL adapter in Rails sets the
class DbslayerAdapter < MysqlAdapter
- VERSION = '0.2.0'
-
def initialize(connection, logger, connection_options, config)
super(connection, logger, connection_options, config)
ActiveRecord::Base.allow_concurrency = true
33 lib/activerecord-dbslayer-adapter.rb
View
@@ -0,0 +1,33 @@
+# Stole this code from Nick Sieger
+begin
+ tried_gem ||= false
+ require 'active_record/version'
+rescue LoadError
+ raise if tried_gem
+ require 'rubygems'
+ gem 'activerecord'
+ tried_gem = true
+ retry
+end
+
+if ActiveRecord::VERSION::MAJOR < 2
+ if defined?(RAILS_CONNECTION_ADAPTERS)
+ RAILS_CONNECTION_ADAPTERS << %q(dbslayer)
+ else
+ RAILS_CONNECTION_ADAPTERS = %w(dbslayer)
+ end
+ if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
+ require 'active_record/connection_adapters/dbslayer_adapter'
+ end
+else
+ require 'active_record'
+ require 'active_record/connection_adapters/dbslayer_adapter'
+end
+
+module ActiveRecord
+ module ConnectionAdapters
+ class DbslayerAdapter
+ VERSION = '0.2.0'
+ end
+ end
+end
5 test/localtest.rb
View
@@ -1,8 +1,5 @@
require 'rubygems'
-$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
-
-require 'active_record'
-require 'active_record/connection_adapters/dbslayer_adapter'
+require 'activerecord-dbslayer-adapter'
ActiveRecord::Base.establish_connection({
:adapter => 'dbslayer',
Please sign in to comment.
Something went wrong with that request. Please try again.