Browse Source

Merge remote-tracking branch 'gdamjan/master' into python-update

INADA Naoki 12 years ago
parent
commit
e96df2d572

+ 1 - 1
netty/pom.xml

@@ -12,7 +12,7 @@
     <dependency>
     <dependency>
     	<groupId>io.netty</groupId>
     	<groupId>io.netty</groupId>
     	<artifactId>netty-codec-http</artifactId>
     	<artifactId>netty-codec-http</artifactId>
-    	<version>4.0.0.CR7-SNAPSHOT</version>
+    	<version>4.0.0.CR7</version>
     </dependency>
     </dependency>
 	 <dependency>
 	 <dependency>
 		<groupId>com.fasterxml.jackson.core</groupId>
 		<groupId>com.fasterxml.jackson.core</groupId>

+ 5 - 1
plain/benchmark_config

@@ -5,7 +5,11 @@
             "setup_file" : "setup",
             "setup_file" : "setup",
             "json_url" : "/json",
             "json_url" : "/json",
             "plaintext_url": "/plaintext",
             "plaintext_url": "/plaintext",
-            "port": 8080,
+            "db_url": "/db",
+            "query_url": "/db?queries=",
+            "update_url": "/update?queries=",
+            "fortune_url": "/fortunes",
+            "port": 9080,
             "sort": 143
             "sort": 143
             }
             }
         }
         }

+ 16 - 10
plain/build.sbt

@@ -9,7 +9,7 @@ organization := "com.ibm"
 
 
 scalaVersion := "2.10.2"
 scalaVersion := "2.10.2"
 
 
-version := "1.0"
+version := "1.0.1"
 
 
 test in Compile := {}
 test in Compile := {}
 
 
@@ -27,25 +27,31 @@ scalacOptions in Compile ++= Seq(
 libraryDependencies ++= Seq(
 libraryDependencies ++= Seq(
   "org.scala-lang" % "scala-reflect" % "2.10.2",
   "org.scala-lang" % "scala-reflect" % "2.10.2",
   "org.reflections" % "reflections" % "0.9.8",
   "org.reflections" % "reflections" % "0.9.8",
-  "com.typesafe" % "config" % "1.0.1",
-  "ch.qos.logback" % "logback-classic" % "1.0.12",
+  "com.typesafe" % "config" % "1.0.2",
+  "ch.qos.logback" % "logback-classic" % "1.0.13",
   "org.codehaus.janino" % "janino" % "2.6.1",
   "org.codehaus.janino" % "janino" % "2.6.1",
-  "com.lmax" % "disruptor" % "3.1.0",
-  "com.typesafe.akka" %% "akka-actor" % "2.1.4",
-  "com.typesafe.akka" %% "akka-slf4j" % "2.1.4",
+  "com.lmax" % "disruptor" % "3.1.1",
+  "com.typesafe.akka" %% "akka-actor" % "2.2.0",
+  "com.typesafe.akka" %% "akka-slf4j" % "2.2.0",
   "org.apache.commons" % "commons-lang3" % "3.1",
   "org.apache.commons" % "commons-lang3" % "3.1",
-  "org.apache.commons" % "commons-compress" % "1.4.1",
+  "org.apache.commons" % "commons-compress" % "1.5",
   "commons-io" % "commons-io" % "2.4",
   "commons-io" % "commons-io" % "2.4",
-  "commons-net" % "commons-net" % "3.2",
-  "commons-codec" % "commons-codec" % "1.7",
+  "commons-net" % "commons-net" % "3.3",
+  "commons-codec" % "commons-codec" % "1.8",
   "com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.3.2",
   "com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.3.2",
   "net.jpountz.lz4" % "lz4" % "1.1.2",
   "net.jpountz.lz4" % "lz4" % "1.1.2",
   "com.fasterxml.jackson.core" % "jackson-databind" % "2.2.2",
   "com.fasterxml.jackson.core" % "jackson-databind" % "2.2.2",
   "com.sun.jersey" % "jersey-json" % "1.17.1",
   "com.sun.jersey" % "jersey-json" % "1.17.1",
-  "org.jvnet.mimepull" % "mimepull" % "1.9.2",
+  "org.jvnet.mimepull" % "mimepull" % "1.9.3",
+  "org.apache.derby" % "derby" % "10.10.1.1",
+  "org.apache.derby" % "derbyclient" % "10.10.1.1",
+  "com.h2database" % "h2" % "1.3.172",
+  "mysql" % "mysql-connector-java" % "5.1.25",
   "javax.servlet" % "servlet-api" % "2.5"
   "javax.servlet" % "servlet-api" % "2.5"
 )
 )
 
 
 Revolver.settings
 Revolver.settings
 
 
 sbtassembly.Plugin.assemblySettings
 sbtassembly.Plugin.assemblySettings
+
+scalariformSettings

BIN
plain/lib/plain-library_2.10-1.0.1-SNAPSHOT.jar


+ 2 - 2
plain/setup.py

@@ -6,8 +6,8 @@ import os
 
 
 def start(args=None):
 def start(args=None):
     subprocess.check_call("./sbt assembly", shell=True, cwd="plain")
     subprocess.check_call("./sbt assembly", shell=True, cwd="plain")
-    subprocess.Popen("java -Xmx4g -Xss8m -jar target/scala-2.10/plain-benchmark-assembly-1.0.jar", cwd="plain", shell=True)
-    time.sleep(5)
+    subprocess.Popen("java -server -Xnoclassgc -XX:MaxPermSize=1g -XX:ReservedCodeCacheSize=384m -Xmx8g -Xss8m -Xmn4g -jar target/scala-2.10/plain-benchmark-assembly-1.0.1.jar", cwd="plain", shell=True)
+    time.sleep(10)
     return 0
     return 0
 
 
 def stop():
 def stop():

+ 32 - 8
plain/src/main/resources/application.conf

@@ -2,17 +2,41 @@
 # application.conf
 # application.conf
 #
 #
 
 
-akka.event-handlers = [ "akka.event.slf4j.Slf4jEventHandler" ]
-akka.loglevel = WARNING
+akka {
+	loggers = [ "akka.event.slf4j.Slf4jLogger" ]
+	loglevel = OFF
+	stdout-loglevel = OFF
+}
 
 
-plain.logging.level = INFO
-plain.http.startup-servers = [ benchmark-server ]
+plain {
+	logging.level = INFO
+	aio.send-receive-buffer-size = 1m
+	http.startup-servers = [ benchmark-server ]
+	jdbc.startup-connection-factories = [ benchmark-mysql ]
+}
 
 
-benchmark-server.port-range = [ 8080 ]
-benchmark-server.dispatcher = benchmark-dispatcher
+benchmark-server {
+	port-range = [ 9080 ]
+	dispatcher = benchmark-dispatcher
+}
 
 
 benchmark-dispatcher.routes = [ 
 benchmark-dispatcher.routes = [ 
-	{ uri = plaintext, resource-class-name = com.ibm.techempower.PlainTextResource }
-	{ uri = json, resource-class-name = com.ibm.techempower.JsonResource }
+	{ uri = plaintext, resource-class-name = com.ibm.techempower.PlainText }
+	{ uri = json, resource-class-name = com.ibm.techempower.Json }
+	{ uri = db, resource-class-name = com.ibm.techempower.Db }
+	{ uri = update, resource-class-name = com.ibm.techempower.Update }
+	{ uri = fortunes, resource-class-name = com.ibm.techempower.Fortunes }
 ]
 ]
 
 
+benchmark-mysql {
+	name = MysqlBenchmark
+	driver = mysql-5-6-12
+	datasource-settings {	
+		setUrl = "jdbc:mysql://127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&dontTrackOpenResources=true&enableQueryTimeouts=false&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=1024&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=true&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true&poolPreparedStatements=true&maxOpenPreparedStatements=100"
+		setUser = "benchmarkdbuser"
+		setPassword = "benchmarkdbpass"
+	}	
+	min-pool-size = 16
+	max-pool-size = 128
+}
+

+ 81 - 0
plain/src/main/scala/com/ibm/techempower/Db.scala

@@ -0,0 +1,81 @@
+package com.ibm.techempower
+
+import java.util.concurrent.ThreadLocalRandom.{ current => random }
+
+import scala.language.implicitConversions
+import scala.language.postfixOps
+
+import com.ibm.plain.rest.{ Form, Resource }
+import com.ibm.plain.json.{ Json => J }
+import com.ibm.plain.jdbc.withConnection
+import com.ibm.plain.jdbc.ConnectionHelper._
+
+final class Db
+
+    extends DbResource {
+
+  Get { get(None) }
+
+  Get { form: Form => get(Some(form)) }
+
+}
+
+final class Update
+
+    extends DbResource {
+
+  Get { form: Form => update(form) }
+
+}
+
+sealed abstract class DbResource
+
+    extends Resource {
+
+  @inline protected[this] final def get(form: Option[Form]): J = {
+    var list: List[J] = Nil
+    val q = form match { case None => 1 case Some(f) => queries(f) }
+    withConnection(datasource) {
+      implicit connection => for (i <- 1 to q) { for (j <- selectsql << next <<! asJson) { list = j :: list } }
+    }
+    form match { case None => list.head case _ => J(list) }
+  }
+
+  @inline protected[this] final def update(form: Form): J = {
+    var list: List[J] = Nil
+    val q = queries(form)
+    withConnection(datasource) {
+      implicit connection =>
+        for (i <- 1 to q) {
+          val id = next
+          val randomNumber = next
+          updatesql << randomNumber << id <<!!;
+          list = asJson(id, randomNumber) :: list
+        }
+    }
+    J(list)
+  }
+
+  @inline private[this] final def queries(form: Form) = try {
+    form.get("queries").get.head.toInt match {
+      case q if 1 > q => 1
+      case q if 500 < q => 500
+      case q => q
+    }
+  } catch {
+    case _: Throwable => 1
+  }
+
+  @inline private[this] final def asJson = (r: RichResultSet) => J(Map("id" -> r.nextInt.get, "randomNumber" -> r.nextInt.get))
+
+  @inline private[this] final def asJson(id: Int, randomNumber: Int) = J(Map("id" -> id, "randomNumber" -> randomNumber))
+
+  @inline private[this] final def next = random.nextInt(1, 10001)
+
+  private[this] final val selectsql = "select id, randomNumber from World where id = ?"
+
+  private[this] final val updatesql = "update World set randomNumber = ? where id = ?"
+
+  private[this] final val datasource = "MysqlBenchmark"
+
+}

+ 41 - 0
plain/src/main/scala/com/ibm/techempower/Fortunes.scala

@@ -0,0 +1,41 @@
+package com.ibm.techempower
+
+import scala.collection.mutable.ListBuffer
+import scala.language.implicitConversions
+import scala.xml._
+
+import com.ibm.plain.rest.Resource
+import com.ibm.plain.jdbc.withConnection
+import com.ibm.plain.jdbc.ConnectionHelper._
+
+final class Fortunes
+
+    extends Resource {
+
+  Get {
+    val list = new ListBuffer[(Int, String)]
+    withConnection(datasource) { implicit c => for (row <- sql <<! asRow) { list += row } }
+    list += ((0, "Additional fortune added at request time."))
+    html(rows(list.sortBy(_._2))).toString
+  }
+
+  @inline private[this] final def asRow = (r: RichResultSet) => (r.nextInt.get, r.nextString.get)
+
+  @inline private[this] final def rows(list: ListBuffer[(Int, String)]) = list.map { e => row(e._1, e._2) }
+
+  @inline private[this] final def row(id: Int, message: String) = <tr><td>{ id }</td><td>{ message }</td></tr>
+
+  @inline private[this] final def html(rows: ListBuffer[Elem]) =
+    <html>
+      <head><title>Fortunes</title></head>
+      <body>  <table>
+                <tr><th>id</th><th>message</th></tr>
+                { rows }
+              </table> </body>
+    </html>
+
+  private[this] final val sql = "select id, message from Fortune"
+
+  private[this] final val datasource = "MysqlBenchmark"
+
+}

+ 12 - 0
plain/src/main/scala/com/ibm/techempower/Json.scala

@@ -0,0 +1,12 @@
+package com.ibm.techempower
+
+import com.ibm.plain.rest.Resource
+import com.ibm.plain.json.{ Json => J }
+
+final class Json
+
+    extends Resource {
+
+  Get { J(Map("message" -> "Hello, World!")) }
+
+}

+ 0 - 12
plain/src/main/scala/com/ibm/techempower/JsonResource.scala

@@ -1,12 +0,0 @@
-package com.ibm.techempower
-
-import com.ibm.plain.rest.Resource
-import com.ibm.plain.json.Json
-
-final class JsonResource
-
-  extends Resource {
-
-  Get { Json(Map("message" -> "Hello, World!")) }
-
-}

+ 22 - 0
plain/src/main/scala/com/ibm/techempower/PlainText.scala

@@ -0,0 +1,22 @@
+package com.ibm.techempower
+
+import java.nio.ByteBuffer
+
+import com.ibm.plain.rest.Resource
+import com.ibm.plain.text.`UTF-8`
+
+final class PlainText
+
+    extends Resource {
+
+  import PlainText._
+
+  Get { hello }
+
+}
+
+object PlainText {
+
+  private final val hello = "Hello, World!".getBytes(`UTF-8`)
+
+}

+ 0 - 20
plain/src/main/scala/com/ibm/techempower/PlainTextResource.scala

@@ -1,20 +0,0 @@
-package com.ibm.techempower
-
-import com.ibm.plain.rest.Resource
-import com.ibm.plain.text.`UTF-8`
-
-final class PlainTextResource
-
-  extends Resource {
-  
-  import PlainTextResource._
-
-  Get { hello }
-
-}
-
-object PlainTextResource {
-  
-  final val hello = "Hello, World!".getBytes(`UTF-8`)  
-  
-}

+ 1 - 1
undertow/pom.xml

@@ -13,7 +13,7 @@
         <dependency>
         <dependency>
             <groupId>io.undertow</groupId>
             <groupId>io.undertow</groupId>
             <artifactId>undertow-core</artifactId>
             <artifactId>undertow-core</artifactId>
-            <version>1.0.0.Beta1</version>
+            <version>1.0.0.Beta3</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>org.jboss.xnio</groupId>
             <groupId>org.jboss.xnio</groupId>

+ 3 - 1
undertow/src/main/java/hello/CacheHandler.java

@@ -9,6 +9,8 @@ import io.undertow.util.Headers;
 
 
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.JSON_UTF8;
+
 /**
 /**
  * Handles the cache access test.
  * Handles the cache access test.
  */
  */
@@ -30,7 +32,7 @@ final class CacheHandler implements HttpHandler {
       worlds[i] = worldCache.get(Helper.randomWorld());
       worlds[i] = worldCache.get(Helper.randomWorld());
     }
     }
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        Headers.CONTENT_TYPE, JSON_UTF8);
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
   }
   }
 }
 }

+ 3 - 1
undertow/src/main/java/hello/DbMongoHandler.java

@@ -11,6 +11,8 @@ import io.undertow.util.Headers;
 
 
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.JSON_UTF8;
+
 /**
 /**
  * Handles the single- and multiple-query database tests using MongoDB.
  * Handles the single- and multiple-query database tests using MongoDB.
  */
  */
@@ -43,7 +45,7 @@ final class DbMongoHandler implements HttpHandler {
           ((Number) object.get("randomNumber")).intValue());
           ((Number) object.get("randomNumber")).intValue());
     }
     }
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        Headers.CONTENT_TYPE, JSON_UTF8);
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
   }
   }
 }
 }

+ 3 - 1
undertow/src/main/java/hello/DbSqlHandler.java

@@ -12,6 +12,8 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSet;
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.JSON_UTF8;
+
 /**
 /**
  * Handles the single- and multiple-query database tests using a SQL database.
  * Handles the single- and multiple-query database tests using a SQL database.
  */
  */
@@ -48,7 +50,7 @@ final class DbSqlHandler implements HttpHandler {
       }
       }
     }
     }
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        Headers.CONTENT_TYPE, JSON_UTF8);
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
   }
   }
 }
 }

+ 3 - 1
undertow/src/main/java/hello/FortunesMongoHandler.java

@@ -16,6 +16,8 @@ import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.HTML_UTF8;
+
 /**
 /**
  * Handles the fortunes test using MongoDB.
  * Handles the fortunes test using MongoDB.
  */
  */
@@ -48,7 +50,7 @@ final class FortunesMongoHandler implements HttpHandler {
     StringWriter writer = new StringWriter();
     StringWriter writer = new StringWriter();
     mustache.execute(writer, fortunes);
     mustache.execute(writer, fortunes);
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.HTML_UTF_8.toString());
+        Headers.CONTENT_TYPE, HTML_UTF8);
     exchange.getResponseSender().send(writer.toString());
     exchange.getResponseSender().send(writer.toString());
   }
   }
 }
 }

+ 3 - 1
undertow/src/main/java/hello/FortunesSqlHandler.java

@@ -17,6 +17,8 @@ import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.HTML_UTF8;
+
 /**
 /**
  * Handles the fortunes test using a SQL database.
  * Handles the fortunes test using a SQL database.
  */
  */
@@ -54,7 +56,7 @@ final class FortunesSqlHandler implements HttpHandler {
     StringWriter writer = new StringWriter();
     StringWriter writer = new StringWriter();
     mustache.execute(writer, fortunes);
     mustache.execute(writer, fortunes);
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.HTML_UTF_8.toString());
+        Headers.CONTENT_TYPE, HTML_UTF8);
     exchange.getResponseSender().send(writer.toString());
     exchange.getResponseSender().send(writer.toString());
   }
   }
 }
 }

+ 9 - 0
undertow/src/main/java/hello/HelloWebServer.java

@@ -6,6 +6,7 @@ import com.github.mustachejava.MustacheFactory;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.cache.LoadingCache;
+import com.google.common.net.MediaType;
 import com.mongodb.DB;
 import com.mongodb.DB;
 import com.mongodb.MongoClient;
 import com.mongodb.MongoClient;
 import io.undertow.Handlers;
 import io.undertow.Handlers;
@@ -34,6 +35,14 @@ import java.util.Properties;
  */
  */
 public final class HelloWebServer {
 public final class HelloWebServer {
 
 
+  //MediaType.toString() does non-trivial work and does not cache the result
+  //so we cache it here
+  public static final String JSON_UTF8 = MediaType.JSON_UTF_8.toString();
+
+  public static final String TEXT_PLAIN = MediaType.PLAIN_TEXT_UTF_8.toString();
+
+  public static final String HTML_UTF8 = MediaType.HTML_UTF_8.toString();
+
   public static void main(String[] args) throws Exception {
   public static void main(String[] args) throws Exception {
     new HelloWebServer();
     new HelloWebServer();
   }
   }

+ 3 - 1
undertow/src/main/java/hello/JsonHandler.java

@@ -9,6 +9,8 @@ import io.undertow.util.Headers;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.JSON_UTF8;
+
 /**
 /**
  * Handles the JSON test.
  * Handles the JSON test.
  */
  */
@@ -22,7 +24,7 @@ final class JsonHandler implements HttpHandler {
   @Override
   @Override
   public void handleRequest(HttpServerExchange exchange) throws Exception {
   public void handleRequest(HttpServerExchange exchange) throws Exception {
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        Headers.CONTENT_TYPE, JSON_UTF8);
     exchange.getResponseSender().send(
     exchange.getResponseSender().send(
         objectMapper.writeValueAsString(
         objectMapper.writeValueAsString(
             Collections.singletonMap("message", "Hello, World!")));
             Collections.singletonMap("message", "Hello, World!")));

+ 3 - 1
undertow/src/main/java/hello/PlaintextHandler.java

@@ -5,6 +5,8 @@ import io.undertow.server.HttpHandler;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.util.Headers;
 import io.undertow.util.Headers;
 
 
+import static hello.HelloWebServer.TEXT_PLAIN;
+
 /**
 /**
  * Handles the plaintext test.
  * Handles the plaintext test.
  */
  */
@@ -12,7 +14,7 @@ final class PlaintextHandler implements HttpHandler {
   @Override
   @Override
   public void handleRequest(HttpServerExchange exchange) throws Exception {
   public void handleRequest(HttpServerExchange exchange) throws Exception {
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8.toString());
+        Headers.CONTENT_TYPE, TEXT_PLAIN);
     exchange.getResponseSender().send("Hello, World!");
     exchange.getResponseSender().send("Hello, World!");
   }
   }
 }
 }

+ 3 - 1
undertow/src/main/java/hello/UpdatesMongoHandler.java

@@ -11,6 +11,8 @@ import io.undertow.util.Headers;
 
 
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.JSON_UTF8;
+
 /**
 /**
  * Handles the updates test using MongoDB.
  * Handles the updates test using MongoDB.
  */
  */
@@ -48,7 +50,7 @@ final class UpdatesMongoHandler implements HttpHandler {
       worlds[i] = new World(id, newRandomNumber);
       worlds[i] = new World(id, newRandomNumber);
     }
     }
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        Headers.CONTENT_TYPE, JSON_UTF8);
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
   }
   }
 }
 }

+ 3 - 1
undertow/src/main/java/hello/UpdatesSqlHandler.java

@@ -12,6 +12,8 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSet;
 import java.util.Objects;
 import java.util.Objects;
 
 
+import static hello.HelloWebServer.JSON_UTF8;
+
 /**
 /**
  * Handles the updates test using a SQL database.
  * Handles the updates test using a SQL database.
  */
  */
@@ -56,7 +58,7 @@ final class UpdatesSqlHandler implements HttpHandler {
       }
       }
     }
     }
     exchange.getResponseHeaders().put(
     exchange.getResponseHeaders().put(
-        Headers.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        Headers.CONTENT_TYPE, JSON_UTF8);
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
     exchange.getResponseSender().send(objectMapper.writeValueAsString(worlds));
   }
   }
 }
 }

+ 19 - 0
uwsgi/README.md

@@ -0,0 +1,19 @@
+# WSGI Benchmarking Test
+
+This is the WSGI portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+
+* [JSON test controller/view](hello.py)
+
+## Infrastructure Software Versions
+The tests were run with:
+* [Python 2.7.3](http://www.python.org/)
+* [uwsgi 1.9.14](https://uwsgi-docs.readthedocs.org/)
+
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost:8080/json

+ 0 - 0
uwsgi/__init__.py


+ 11 - 0
uwsgi/benchmark_config

@@ -0,0 +1,11 @@
+{
+  "framework": "uwsgi",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "port": 8080,
+      "sort": 29
+    }
+  }]
+}

+ 14 - 0
uwsgi/hello.py

@@ -0,0 +1,14 @@
+import ujson
+
+
+def application(environ, start_response):
+    response = {
+      "message": "Hello, World!"
+    }
+    data = ujson.dumps(response)
+    response_headers = [
+        ('Content-type', 'text/plain'),
+        ('Content-Length', str(len(data)))
+    ]
+    start_response('200 OK', response_headers)
+    return [data]

+ 5 - 0
uwsgi/requirements.txt

@@ -0,0 +1,5 @@
+greenlet
+cython
+-e git://github.com/surfly/gevent.git#egg=gevent
+uwsgi
+ujson

+ 17 - 0
uwsgi/setup.py

@@ -0,0 +1,17 @@
+
+import subprocess
+import sys
+import setup_util
+
+
+def start(args):
+    subprocess.Popen('uwsgi --gevent 1000 --http :8080 -w hello --pidfile /tmp/uwsgi.pid', shell=True, cwd="uwsgi")
+    return 0
+
+
+def stop():
+    try:
+        subprocess.Popen('uwsgi --stop /tmp/uwsgi.pid', shell=True, cwd="uwsgi")
+    except OSError:
+        pass
+    return 0