README.md in swift-0.14.0 vs README.md in swift-1.0.0

- old
+ new

@@ -8,38 +8,48 @@ A rational rudimentary object relational mapper. ## Dependencies -* ruby >= 1.9.1 -* [dbic++](http://github.com/deepfryed/dbicpp) >= 0.6.0 -* mysql >= 5.0.17, postgresql >= 8.4 or sqlite3 >= 3.7 +* MRI Ruby >= 1.9.1 +* swift-db-sqlite3 or swift-db-postgres or swift-db-mysql +## Installation + +### Dependencies + +Install one of the following drivers you would like to use. + +``` +gem install swift-db-sqlite3 +gem install swift-db-postgres +gem install swift-db-mysql +``` + +### Install Swift + +``` +gem install swift +``` + ## Features * Multiple databases. * Prepared statements. * Bind values. * Transactions and named save points. * Asynchronous API for PostgreSQL and MySQL. * IdentityMap. * Migrations. -## Performance notes - -1. The current version creates DateTime objects for timestamp fields and this is roughly 80% slower on - rubies older than 1.9.3. -2. On rubies older than 1.9.3, Swift will try using [home_run](https://github.com/jeremyevans/home_run) - for performance. - ### DB ```ruby require 'swift' Swift.trace true # Debugging. - Swift.setup :default, Swift::DB::Postgres, db: 'swift' + Swift.setup :default, Swift::Adapter::Postgres, db: 'swift' # Block form db context. Swift.db do |db| db.execute('drop table if exists users') db.execute('create table users(id serial, name text, email text)') @@ -60,34 +70,34 @@ result = db.prepare('select * from users where name like ?').execute('Benny%') puts result.first end ``` -### DB Scheme Operations +### DB Record Operations Rudimentary object mapping. Provides a definition to the db methods for prepared (and cached) statements plus native primitive Ruby type conversion. ```ruby require 'swift' require 'swift/migrations' Swift.trace true # Debugging. - Swift.setup :default, Swift::DB::Postgres, db: 'swift' + Swift.setup :default, Swift::Adapter::Postgres, db: 'swift' - class User < Swift::Scheme + class User < Swift::Record store :users attribute :id, Swift::Type::Integer, serial: true, key: true attribute :name, Swift::Type::String attribute :email, Swift::Type::String attribute :updated_at, Swift::Type::DateTime end # User Swift.db do |db| db.migrate! User - # Select Scheme instance (relation) instead of Hash. + # Select Record instance (relation) instead of Hash. users = db.prepare(User, 'select * from users limit 1').execute # Make a change and update. users.each{|user| user.updated_at = Time.now} db.update(User, *users) @@ -96,22 +106,22 @@ user = db.get(User, id: 1) puts user.name, user.email end ``` -### Scheme CRUD +### Record CRUD -Scheme/relation level helpers. +Record/relation level helpers. ```ruby require 'swift' require 'swift/migrations' Swift.trace true # Debugging. - Swift.setup :default, Swift::DB::Postgres, db: 'swift' + Swift.setup :default, Swift::Adapter::Postgres, db: 'swift' - class User < Swift::Scheme + class User < Swift::Record store :users attribute :id, Swift::Type::Integer, serial: true, key: true attribute :name, Swift::Type::String attribute :email, Swift::Type::String end # User @@ -140,11 +150,11 @@ SQL is easy and most people know it so Swift ORM provides simple #to_s attribute to table and field name typecasting. ```ruby - class User < Swift::Scheme + class User < Swift::Record store :users attribute :id, Swift::Type::Integer, serial: true, key: true attribute :age, Swift::Type::Integer, field: 'ega' attribute :name, Swift::Type::String, field: 'eman' attribute :email, Swift::Type::String, field: 'liame' @@ -165,11 +175,11 @@ ```ruby require 'swift' require 'swift/identity_map' require 'swift/migrations' - class User < Swift::Scheme + class User < Swift::Record store :users attribute :id, Swift::Type::Integer, serial: true, key: true attribute :age, Swift::Type::Integer, field: 'ega' attribute :name, Swift::Type::String, field: 'eman' attribute :email, Swift::Type::String, field: 'liame' @@ -202,11 +212,11 @@ But you can do it almost as fast in ruby, ```ruby require 'swift' - Swift.setup :default, Swift::DB::Mysql, db: 'swift' + Swift.setup :default, Swift::Adapter::Mysql, db: 'swift' # MySQL packet size is the usual limit, 8k is the packet size by default. Swift.db do |db| File.open('/tmp/users.tab') do |file| count = db.write('users', %w{name email balance}, file) @@ -224,11 +234,11 @@ which implicitly uses `rb_thread_wait_fd` ```ruby require 'swift' - pool = 3.times.map.with_index {|n| Swift.setup n, Swift::DB::Postgres, db: 'swift' } + pool = 3.times.map.with_index {|n| Swift.setup n, Swift::Adapter::Postgres, db: 'swift' } Thread.new do pool[0].async_execute('select pg_sleep(3), 1 as qid') {|row| p row} end @@ -241,35 +251,47 @@ end Thread.list.reject {|thread| Thread.current == thread}.each(&:join) ``` +or use the `swift/eventmachine` api. + ```ruby - require 'swift' - require 'eventmachine' - - pool = 3.times.map.with_index {|n| Swift.setup n, Swift::DB::Postgres, db: 'swift'} - - module Handler - attr_reader :result - - def initialize result - @result = result + require 'swift/eventmachine' + + EM.run do + pool = 3.times.map { Swift.setup(:default, Swift::Adapter::Postgres, db: "swift") } + + 3.times.each do |n| + defer = pool[n].execute("select pg_sleep(3 - #{n}), #{n + 1} as qid") + + defer.callback do |res| + p res.first + end + + defer.errback do |e| + p 'error', e + end end - - def notify_readable - result.retrieve - result.each {|row| p row } - unbind - end end - +``` + +or use the `em-synchrony` api for `swift` + +```ruby + require 'swift/synchrony' + EM.run do - EM.watch(pool[0].fileno, Handler, pool[0].async_execute('select pg_sleep(3), 1 as qid')){|c| c.notify_readable = true} - EM.watch(pool[1].fileno, Handler, pool[1].async_execute('select pg_sleep(2), 2 as qid')){|c| c.notify_readable = true} - EM.watch(pool[2].fileno, Handler, pool[2].async_execute('select pg_sleep(1), 3 as qid')){|c| c.notify_readable = true} - EM.add_timer(4) { EM.stop } + 3.times.each do |n| + EM.synchrony do + db = Swift.setup(:default, Swift::Adapter::Postgres, db: "swift") + result = db.execute("select pg_sleep(3 - #{n}), #{n + 1} as qid") + + p result.first + EM.stop if n == 0 + end + end end ``` ## Performance @@ -282,13 +304,40 @@ #### ORM The test environment: -* ruby 1.9.3p0 -* Intel Core2Duo P8700 2.53GHz, 4G RAM and Kingston SATA2 SSD +``` +$ uname -a +Linux deepfryed.local 3.0.0-1-amd64 #1 SMP Sun Jul 24 02:24:44 UTC 2011 x86_64 GNU/Linux + +$ cat /proc/cpuinfo | grep "processor\|model name" + +processor : 0 +model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz +processor : 1 +model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz +processor : 2 +model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz +processor : 3 +model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz + +$ ruby -v + +ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux] +``` + +PostgreSQL config: + +``` +shared_buffers = 800MB # min 128kB +effective_cache_size = 512MB +work_mem = 64MB # min 64kB +maintenance_work_mem = 64MB # min 1MB +``` + The test setup: * 10,000 rows are created once. * All the rows are selected once. * All the rows are selected once and updated once. @@ -298,28 +347,28 @@ the actual memory consumption might be much lower than the numbers below. ``` ./simple.rb -n1 -r10000 -s ar -s dm -s sequel -s swift - benchmark sys user total real rss - ar #create 0.75 7.18 7.93 10.5043 366.95m - ar #select 0.07 0.26 0.33 0.3680 40.71m - ar #update 0.96 7.92 8.88 11.7537 436.38m + benchmark sys user total real rss - dm #create 0.33 3.73 4.06 5.0908 245.68m - dm #select 0.08 1.51 1.59 1.6154 87.95m - dm #update 0.44 7.09 7.53 8.8685 502.77m + ar #create 1.960000 15.81000 17.770000 22.753109 266.21m + ar #select 0.020000 0.38000 0.400000 0.433041 50.82m + ar #update 2.000000 17.90000 19.900000 26.674921 317.48m - sequel #create 0.60 5.07 5.67 7.9804 236.69m - sequel #select 0.02 0.12 0.14 0.1778 12.75m - sequel #update 0.82 4.95 5.77 8.2062 230.00m + dm #create 0.660000 11.55000 12.210000 15.592424 236.86m + dm #select 0.030000 1.30000 1.330000 1.351911 87.18m + dm #update 0.950000 17.25000 18.200000 22.109859 474.81m - swift #create 0.27 0.59 0.86 1.5085 84.85m - swift #select 0.03 0.06 0.09 0.1037 11.24m - swift #update 0.20 0.69 0.89 1.5867 62.19m + sequel #create 1.960000 14.48000 16.440000 23.004864 226.68m + sequel #select 0.000000 0.09000 0.090000 0.134619 12.77m + sequel #update 1.900000 14.37000 16.270000 22.945636 200.20m - -- bulk insert api -- - swift #write 0.04 0.06 0.10 0.1699 14.05m + swift #create 0.520000 1.95000 2.470000 5.828846 75.26m + swift #select 0.010000 0.070000 0.080000 0.095124 11.23m + swift #update 0.440000 1.95000 2.390000 6.044971 59.35m + swift #write 0.010000 0.050000 0.060000 0.117195 13.46m + ``` ## TODO * More tests.