Browse Source

Update crystal benchmarks for 1.0 release (#6530)

* Update crystal benchmarks for 1.0 release

* Modify how updates and queries endpoints work

* More minor tweaks

* Try tweaking the database config
Matthew McGarvey 4 years ago
parent
commit
b9d8851f1b

+ 9 - 8
frameworks/Crystal/crystal/crystal-radix.dockerfile

@@ -1,18 +1,19 @@
-FROM crystallang/crystal:0.26.1
+FROM crystallang/crystal:1.0.0
 
 WORKDIR /crystal
+COPY shard.yml shard.yml
+COPY shard.lock shard.lock
+RUN shards install
+
 COPY views views
-COPY run-radix.sh run-radix.sh
+COPY run.sh run.sh
 COPY server_radix.cr server_radix.cr
-COPY shard.lock shard.lock
-COPY shard.yml shard.yml
 
 ENV GC_MARKERS 1
-ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_pool_size=56&max_idle_pool_size=56
+ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56
 
-RUN shards install
-RUN crystal build --release --no-debug server_radix.cr -o server_radix.out
+RUN crystal build --release --no-debug server_radix.cr -o server.out
 
 EXPOSE 8080
 
-CMD bash run-radix.sh
+CMD bash run.sh

+ 6 - 5
frameworks/Crystal/crystal/crystal.dockerfile

@@ -1,16 +1,17 @@
-FROM crystallang/crystal:0.26.1
+FROM crystallang/crystal:1.0.0
 
 WORKDIR /crystal
+COPY shard.yml shard.yml
+COPY shard.lock shard.lock
+RUN shards install
+
 COPY views views
 COPY run.sh run.sh
 COPY server.cr server.cr
-COPY shard.lock shard.lock
-COPY shard.yml shard.yml
 
 ENV GC_MARKERS 1
-ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_pool_size=56&max_idle_pool_size=56
+ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56
 
-RUN shards install
 RUN crystal build --release --no-debug server.cr -o server.out
 
 EXPOSE 8080

+ 0 - 7
frameworks/Crystal/crystal/run-radix.sh

@@ -1,7 +0,0 @@
-#!/bin/bash
-
-for i in $(seq 1 $(nproc --all)); do
-  ./server_radix.out &
-done
-
-wait

+ 26 - 43
frameworks/Crystal/crystal/server.cr

@@ -5,88 +5,71 @@ require "ecr"
 
 APPDB = DB.open(ENV["DATABASE_URL"])
 ID_MAXIMUM = 10_000
+CONTENT_HTML = "text/html; charset=UTF-8"
+CONTENT_JSON = "application/json"
+CONTENT_TEXT = "text/plain"
 
 server = HTTP::Server.new do |context|
   response = context.response
   request = context.request
 
   response.headers["Server"] = "Crystal"
-  response.headers["Date"] = HTTP.format_time(Time.now)
+  response.headers["Date"] = HTTP.format_time(Time.local)
 
   case request.path
   when "/json"
     response.status_code = 200
-    response.headers["Content-Type"] = "application/json"
+    response.headers["Content-Type"] = CONTENT_JSON
     {message: "Hello, World!"}.to_json(response)
   when "/plaintext"
     response.status_code = 200
-    response.headers["Content-Type"] = "text/plain"
+    response.headers["Content-Type"] = CONTENT_TEXT
     response.print "Hello, World!"
   when "/db"
     response.status_code = 200
-    response.headers["Content-Type"] = "application/json"
-    random_world.to_json(response)
+    response.headers["Content-Type"] = CONTENT_JSON
+    find_world(rand(1..ID_MAXIMUM)).to_json(response)
   when "/queries"
     response.status_code = 200
-    response.headers["Content-Type"] = "application/json"
+    response.headers["Content-Type"] = CONTENT_JSON
 
-    JSON.build(response) do |json|
-      json.array do
-        sanitized_query_count(request).times do
-          random_world.to_json(json)
-        end
-      end
-    end
+    worlds = (1..sanitized_query_count(request)).map { find_world(rand(1..ID_MAXIMUM)) }
+    worlds.to_json(response)
   when "/fortunes"
     response.status_code = 200
-    response.headers["Content-Type"] = "text/html; charset=UTF-8"
+    response.headers["Content-Type"] = CONTENT_HTML
+
+    data = APPDB.query_all("SELECT id, message FROM Fortune", as: {id: Int32, message: String})
 
-    data = fortunes
     additional_fortune = {
       id:      0,
       message: "Additional fortune added at request time.",
     }
 
     data.push(additional_fortune)
-    data.sort! { |f1, f2| f1[:message] <=> f2[:message] }
+    data.sort_by! { |fortune| fortune[:message] }
 
     ECR.embed "views/fortunes.ecr", response
   when "/updates"
     response.status_code = 200
-    response.headers["Content-Type"] = "application/json"
-
-    JSON.build(response) do |json|
-      json.array do
-        sanitized_query_count(request).times do
-          world = set_world({id: random_world[:id], randomNumber: rand(1..ID_MAXIMUM)})
-          world.to_json(json)
-        end
+    response.headers["Content-Type"] = CONTENT_JSON
+    worlds = (1..sanitized_query_count(request)).map do
+      world = find_world(rand(1..ID_MAXIMUM))
+      random_number = rand(1..ID_MAXIMUM)
+      while random_number == world[:randomNumber]
+        random_number = rand(1..ID_MAXIMUM)
       end
+      APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", random_number, world[:id])
+      {id: world[:id], randomNumber: random_number}
     end
+    worlds.to_json(response)
   else
     response.status_code = 404
   end
 end
 
-private def random_world
-  id = rand(1..ID_MAXIMUM)
-  random_number = APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: Int32)
-  {id: id, randomNumber: random_number}
-end
-
-private def set_world(world)
-  APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", world[:randomNumber], world[:id])
-  world
-end
-
-private def fortunes
-  data = Array(NamedTuple(id: Int32, message: String)).new
-
-  APPDB.query_each("SELECT id, message FROM Fortune") do |rs|
-    data.push({id: rs.read(Int32), message: rs.read(String)})
-  end
-
-  data
+private def find_world(id : Int32)
+  APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: {id: Int32, randomNumber: Int32})
 end
 
 private def sanitized_query_count(request)

+ 53 - 72
frameworks/Crystal/crystal/server_radix.cr

@@ -4,81 +4,82 @@ require "pg"
 require "ecr"
 require "radix"
 
+APPDB = DB.open(ENV["DATABASE_URL"])
+ID_MAXIMUM = 10_000
+CONTENT_HTML = "text/html; charset=UTF-8"
+CONTENT_JSON = "application/json"
+CONTENT_TEXT = "text/plain"
+
 plaintext_handler = ->(context : HTTP::Server::Context) do
-  response = context.response
-  response.status_code = 200
-  response.headers["Content-Type"] = "text/plain"
-  response.print "Hello, World!"
-  return response
+  context.response.tap do |response|
+    response.status_code = 200
+    response.headers["Content-Type"] = CONTENT_TEXT
+    response.print "Hello, World!"
+  end
 end
 
 json_handler = ->(context : HTTP::Server::Context) do
-  response = context.response
-  response.status_code = 200
-  response.headers["Content-Type"] = "application/json"
-  {message: "Hello, World!"}.to_json(response)
-  return response
+  context.response.tap do |response|
+    response.status_code = 200
+    response.headers["Content-Type"] = CONTENT_JSON
+    {message: "Hello, World!"}.to_json(response)
+  end
 end
 
 db_handler = ->(context : HTTP::Server::Context) do
-  request = context.request
-  response = context.response
-  response.status_code = 200
-  response.headers["Content-Type"] = "application/json"
-  random_world.to_json(response)
-  return response
+  context.response.tap do |response|
+    response.status_code = 200
+    response.headers["Content-Type"] = CONTENT_JSON
+    find_world(rand(1..ID_MAXIMUM)).to_json(response)
+  end
 end
 
 queries_handler = ->(context : HTTP::Server::Context) do
   request = context.request
-  response = context.response
-  response.status_code = 200
-  response.headers["Content-Type"] = "application/json"
+  context.response.tap do |response|
+    response.status_code = 200
+    response.headers["Content-Type"] = CONTENT_JSON
 
-  JSON.build(response) do |json|
-    json.array do
-      sanitized_query_count(request).times do
-        random_world.to_json(json)
-      end
-    end
+    worlds = (1..sanitized_query_count(request)).map { find_world(rand(1..ID_MAXIMUM)) }
+    worlds.to_json(response)
   end
-  return response
 end
 
 fortunes_handler = ->(context : HTTP::Server::Context) do
-  request = context.request
-  response = context.response
-  response.status_code = 200
-  response.headers["Content-Type"] = "text/html; charset=UTF-8"
+  context.response.tap do |response|
+    response.status_code = 200
+    response.headers["Content-Type"] = CONTENT_HTML
 
-  data = fortunes
-  additional_fortune = {
-    id:      0,
-    message: "Additional fortune added at request time.",
-  }
+    data = APPDB.query_all("SELECT id, message FROM Fortune", as: {id: Int32, message: String})
+    additional_fortune = {
+      id:      0,
+      message: "Additional fortune added at request time.",
+    }
 
-  data.push(additional_fortune)
-  data.sort! { |f1, f2| f1[:message] <=> f2[:message] }
+    data.push(additional_fortune)
+    data.sort_by! { |fortune| fortune[:message] }
 
-  ECR.embed "views/fortunes.ecr", response
-  return response
+    ECR.embed "views/fortunes.ecr", response
+  end
 end
 
 updates_handler = ->(context : HTTP::Server::Context) do
   request = context.request
-  response = context.response
-  response.status_code = 200
-  response.headers["Content-Type"] = "application/json"
-
-  JSON.build(response) do |json|
-    json.array do
-      sanitized_query_count(request).times do
-        world = set_world({id: random_world[:id], randomNumber: rand(1..ID_MAXIMUM)})
-        world.to_json(json)
+  context.response.tap do |response|
+    response.status_code = 200
+    response.headers["Content-Type"] = "application/json"
+
+    worlds = (1..sanitized_query_count(request)).map do
+      world = find_world(rand(1..ID_MAXIMUM))
+      random_number = rand(1..ID_MAXIMUM)
+      while random_number == world[:randomNumber]
+        random_number = rand(1..ID_MAXIMUM)
       end
+      APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", random_number, world[:id])
+      {id: world[:id], randomNumber: random_number}
     end
+    worlds.to_json(response)
   end
-  return response
 end
 
 tree = Radix::Tree(Proc(HTTP::Server::Context, HTTP::Server::Response)).new
@@ -89,14 +90,11 @@ tree.add "/queries", queries_handler
 tree.add "/fortunes", fortunes_handler
 tree.add "/updates", updates_handler
 
-APPDB = DB.open(ENV["DATABASE_URL"])
-ID_MAXIMUM = 10_000
-
 server = HTTP::Server.new do |context|
   request = context.request
   response = context.response
   response.headers["Server"] = "Crystal"
-  response.headers["Date"] = HTTP.format_time(Time.now)
+  response.headers["Date"] = HTTP.format_time(Time.local)
 
   result = tree.find(request.path)
 
@@ -107,25 +105,8 @@ server = HTTP::Server.new do |context|
   end
 end
 
-private def random_world
-  id = rand(1..ID_MAXIMUM)
-  random_number = APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: Int32)
-  {id: id, randomNumber: random_number}
-end
-
-private def set_world(world)
-  APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", world[:randomNumber], world[:id])
-  world
-end
-
-private def fortunes
-  data = Array(NamedTuple(id: Int32, message: String)).new
-
-  APPDB.query_each("SELECT id, message FROM Fortune") do |rs|
-    data.push({id: rs.read(Int32), message: rs.read(String)})
-  end
-
-  data
+private def find_world(id : Int32)
+  APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: {id: Int32, randomNumber: Int32})
 end
 
 private def sanitized_query_count(request)

+ 7 - 7
frameworks/Crystal/crystal/shard.lock

@@ -1,14 +1,14 @@
-version: 1.0
+version: 2.0
 shards:
   db:
-    github: crystal-lang/crystal-db
-    version: 0.5.0
+    git: https://github.com/crystal-lang/crystal-db.git
+    version: 0.10.1
 
   pg:
-    github: will/crystal-pg
-    version: 0.15.0
+    git: https://github.com/will/crystal-pg.git
+    version: 0.23.2
 
   radix:
-    github: luislavena/radix
-    version: 0.3.8
+    git: https://github.com/luislavena/radix.git
+    version: 0.4.1
 

+ 3 - 3
frameworks/Crystal/crystal/shard.yml

@@ -2,12 +2,12 @@ name: crystal
 version: 0.0.1
 
 license: MIT
+crystal: "~> 1.0"
 
 dependencies:
   pg:
     github: will/crystal-pg
-    version: 0.15.0
-
+    version: ~> 0.23.2
   radix:
     github: luislavena/radix
-    version: 0.3.8
+    version: ~> 0.4.1