Browse Source

[ruby|rack-sequel] Batch update for Postgres (#9130)

Also remove Rack::Chunked middleware as it is no longer supported.
Petrik de Heus 1 year ago
parent
commit
4398d2cad6

+ 27 - 7
frameworks/Ruby/rack-sequel/boot.rb

@@ -33,8 +33,8 @@ def connect(dbtype)
   Bundler.require(dbtype) # Load database-specific modules
 
   adapters = {
-    :mysql=>{ :jruby=>'jdbc:mysql', :mri=>'mysql2' },
-    :postgresql=>{ :jruby=>'jdbc:postgresql', :mri=>'postgres' }
+    mysql: { jruby: 'jdbc:mysql', mri: 'mysql2' },
+    postgresql: { jruby: 'jdbc:postgresql', mri: 'postgres' }
   }
 
   opts = {}
@@ -52,11 +52,11 @@ def connect(dbtype)
 
   Sequel.connect \
     '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % {
-      :adapter=>adapters.fetch(dbtype).fetch(defined?(JRUBY_VERSION) ? :jruby : :mri),
-      :host=>'tfb-database',
-      :database=>'hello_world',
-      :user=>'benchmarkdbuser',
-      :password=>'benchmarkdbpass'
+      adapter: adapters.fetch(dbtype).fetch(defined?(JRUBY_VERSION) ? :jruby : :mri),
+      host: 'tfb-database',
+      database: 'hello_world',
+      user: 'benchmarkdbuser',
+      password: 'benchmarkdbpass'
     }, opts
 end
 
@@ -64,7 +64,27 @@ DB = connect ENV.fetch('DBTYPE').to_sym
 
 # Define ORM models
 class World < Sequel::Model(:World)
+  BY_ID = naked.where(id: :$id).prepare(:first, :world_by_id)
+  UPDATE = where(id: :$id).prepare(:update, :world_update, randomnumber: :$randomnumber)
+
   def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql
+
+  def self.batch_update(worlds)
+    if DB.database_type == :mysql
+      worlds.each do |world|
+        UPDATE.(id: world[:id], randomnumber: world[:randomnumber])
+      end
+    else
+      ids = []
+      sql = String.new("UPDATE world SET randomnumber = CASE id ")
+      worlds.each do |world|
+        sql << "when #{world[:id]} then #{world[:randomnumber]} "
+        ids << world[:id]
+      end
+      sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})"
+      DB.run(sql)
+    end
+  end
 end
 
 class Fortune < Sequel::Model(:Fortune)

+ 0 - 1
frameworks/Ruby/rack-sequel/config.ru

@@ -1,5 +1,4 @@
 require_relative 'boot'
 require_relative 'hello_world'
 use Rack::ContentLength
-use Rack::Chunked
 run HelloWorld.new

+ 13 - 13
frameworks/Ruby/rack-sequel/hello_world.rb

@@ -20,17 +20,14 @@ class HelloWorld
     rand(MAX_PK).succ
   end
 
-  WORLD_BY_ID = World.naked.where(:id=>:$id).prepare(:first, :world_by_id)
-  WORLD_UPDATE = World.where(:id=>:$id).prepare(:update, :world_update, :randomnumber=>:$randomnumber)
-
   def db
-    WORLD_BY_ID.(:id=>rand1)
+    World::BY_ID.(id: rand1)
   end
 
   def queries(env)
     DB.synchronize do
       ALL_IDS.sample(bounded_queries(env)).map do |id|
-        WORLD_BY_ID.(id: id)
+        World::BY_ID.(id: id)
       end
     end
   end
@@ -38,8 +35,8 @@ class HelloWorld
   def fortunes
     fortunes = Fortune.all
     fortunes << Fortune.new(
-      :id=>0,
-      :message=>'Additional fortune added at request time.'
+      id: 0,
+      message: 'Additional fortune added at request time.'
     )
     fortunes.sort_by!(&:message)
 
@@ -78,11 +75,14 @@ class HelloWorld
 
   def updates(env)
     DB.synchronize do
-      ALL_IDS.sample(bounded_queries(env)).map do |id|
-        world = WORLD_BY_ID.(id: id)
-        WORLD_UPDATE.(id: world[:id], randomnumber: (world[:randomnumber] = rand1))
-        world
-      end
+      worlds =
+        ALL_IDS.sample(bounded_queries(env)).map do |id|
+          world = World::BY_ID.(id: id)
+          world[:randomnumber] = rand1
+          world
+        end
+      World.batch_update(worlds)
+      worlds
     end
   end
 
@@ -91,7 +91,7 @@ class HelloWorld
       case env['PATH_INFO']
       when '/json'
         # Test type 1: JSON serialization
-        [JSON_TYPE, JSON.fast_generate(:message=>'Hello, World!')]
+        [JSON_TYPE, JSON.fast_generate(message: 'Hello, World!')]
       when '/db'
         # Test type 2: Single database query
         [JSON_TYPE, JSON.fast_generate(db)]