View
@@ -0,0 +1,37 @@
package inject;
import akka.dispatch.ExecutionContexts;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import play.Configuration;
import play.core.NamedThreadFactory;
import scala.concurrent.ExecutionContext;
public class AppModule extends AbstractModule {
protected void configure() {
}
@Provides @Singleton @Named("dbTpe")
public ThreadPoolExecutor provideThreadPoolExecutor(Configuration configuration) {
int partitionCount = configuration.getInt("db.default.partitionCount");
int maxConnections = partitionCount * configuration.getInt("db.default.maxConnectionsPerPartition");
int minConnections = partitionCount * configuration.getInt("db.default.minConnectionsPerPartition");
return new ThreadPoolExecutor(minConnections, maxConnections,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new NamedThreadFactory("dbEc"));
}
@Provides @Singleton @Named("dbEc")
public ExecutionContext provideExecutionContext(@Named("dbTpe") ThreadPoolExecutor tpe) {
return ExecutionContexts.fromExecutorService(tpe);
}
}
View
@@ -1,7 +1,7 @@
package models;
import com.avaje.ebean.Ebean;
import play.db.ebean.Model;
import com.avaje.ebean.Model;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -21,7 +21,7 @@ public static World find(Long id) {
return Ebean.find(World.class, id);
}
public static List<World> save(final List<World> worlds) throws Throwable {
public static List<World> save(final List<World> worlds) {
worlds.forEach(Ebean::update);
return worlds;
View
@@ -1,9 +1,9 @@
package utils;
import java.util.concurrent.CompletionStage;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import play.libs.F;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;
@@ -13,7 +13,7 @@
private static final DateTimeFormatter RFC_1123_DATE_TIME = DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'").withZoneUTC();
@Override
public F.Promise<Result> call(Http.Context context) throws Throwable {
public CompletionStage<Result> call(Http.Context context) {
context.response().setHeader("Server", "Play2");
context.response().setHeader("Date", RFC_1123_DATE_TIME.print(new DateTime()));
return delegate.call(context);
View
@@ -5,19 +5,24 @@
* condition is not satisfied then a supplied status result is yielded.
*/
import play.libs.F;
import com.google.inject.Injector;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import javax.inject.Inject;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;
public class PredicatedAction extends Action<Predicated> {
@Inject private Injector injector;
@Override
public F.Promise<Result> call(final Http.Context ctx) throws Throwable {
final Predicate p = configuration.predicate().newInstance();
public CompletionStage<Result> call(final Http.Context ctx) {
final Predicate p = injector.getInstance(configuration.predicate());
if (p.condition()) {
return delegate.call(ctx);
} else {
return F.Promise.<Result>pure(status(configuration.failed()));
}
return CompletableFuture.supplyAsync(() -> status(configuration.failed()));
}
}
View
@@ -17,6 +17,9 @@ application.langs="en"
# Default to Global in the root package.
# global=Global
# The dependency injection modules
play.modules.enabled += "inject.AppModule"
# Database configuration
# ~~~~~
# You can declare as many datasources as you want.
View
@@ -1 +1 @@
sbt.version=0.13.9
sbt.version=0.13.15
View
@@ -1,2 +1,2 @@
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.3")
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "1.0.0")
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.14")
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")
View
@@ -20,7 +20,7 @@ This is the Play portion of a [benchmarking test suite](../) comparing a variety
The tests were run with:
* Java 8
* [Play 2.4.2](http://http://www.playframework.com/)
* [Play 2.4.2](https://www.playframework.com/)
## Test URLs
### JSON Encoding Test
View
@@ -1 +1 @@
sbt.version=0.13.9
sbt.version=0.13.15
View
@@ -194,7 +194,7 @@ if (cluster.isMaster) {
updateFunctions.push((callback) => {
worlds[i].randomNumber = Math.ceil(Math.random() * 10000);
MWorld.update({
id: worlds[i]
id: worlds[i].id
}, {
randomNumber: worlds[i].randomNumber
}, callback);
View
@@ -30,9 +30,9 @@ const mongodbGetAllFortunes = (callback) => {
const mongodbDriverUpdateQuery = (callback) => {
collections.World.findOne({id: h.randomTfbNumber()}, (err, world) => {
world.randomnumber = h.randomTfbNumber();
world.randomNumber = h.randomTfbNumber();
collections.World.update({id: world.id}, world, (err, updated) => {
callback(err, { id: world.id, randomnumber: world.randomnumber } );
callback(err, { id: world.id, randomNumber: world.randomNumber } );
});
});
};
View
@@ -1 +1 @@
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip
View
@@ -58,6 +58,11 @@
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
<build>
View
@@ -3,6 +3,7 @@ package org.jetbrains.ktor.benchmarks
import com.google.gson.*
import com.mysql.jdbc.*
import com.zaxxer.hikari.*
import kotlinx.coroutines.experimental.*
import org.jetbrains.ktor.application.*
import org.jetbrains.ktor.content.*
import org.jetbrains.ktor.features.*
@@ -11,8 +12,10 @@ import org.jetbrains.ktor.http.*
import org.jetbrains.ktor.netty.*
import org.jetbrains.ktor.routing.*
import org.jetbrains.ktor.util.*
import java.sql.ResultSet.*
import java.sql.ResultSet.CONCUR_READ_ONLY
import java.sql.ResultSet.TYPE_FORWARD_ONLY
import java.util.concurrent.*
import java.util.concurrent.atomic.*
import javax.sql.*
@@ -27,7 +30,17 @@ fun main(args: Array<String>) {
Driver::class.java.newInstance()
val pool = hikari(dbHost, a, b)
val counter = AtomicInteger()
val databaseExecutor = Executors.newFixedThreadPool(256) { r ->
Thread(r, "db-${counter.incrementAndGet()}-thread")
}
val databaseDispatcher = databaseExecutor.asCoroutineDispatcher()
embeddedServer(Netty, 9090) {
install(SamplingCallLogging) {
samplingFactor = 50000L
}
install(DefaultHeaders)
routing {
get("/plaintext") { call ->
@@ -37,64 +50,72 @@ fun main(args: Array<String>) {
call.respond(TextContent(gson.toJson(Message()), ContentType.Application.Json, HttpStatusCode.OK))
}
get("/db") { call ->
pool.connection.use { connection ->
val random = ThreadLocalRandom.current()
val queries = call.queries()
val result = mutableListOf<World>()
connection.prepareStatement("SELECT * FROM World WHERE id = ?", TYPE_FORWARD_ONLY, CONCUR_READ_ONLY).use { statement ->
for (i in 1..(queries ?: 1)) {
statement.setInt(1, random.nextInt(DbRows) + 1)
statement.executeQuery().use { rs ->
while (rs.next()) {
result += World(rs.getInt("id"), rs.getInt("randomNumber"))
val response = run(databaseDispatcher) {
pool.connection.use { connection ->
val random = ThreadLocalRandom.current()
val queries = call.queries()
val result = mutableListOf<World>()
connection.prepareStatement("SELECT * FROM World WHERE id = ?", TYPE_FORWARD_ONLY, CONCUR_READ_ONLY).use { statement ->
for (i in 1..(queries ?: 1)) {
statement.setInt(1, random.nextInt(DbRows) + 1)
statement.executeQuery().use { rs ->
while (rs.next()) {
result += World(rs.getInt("id"), rs.getInt("randomNumber"))
}
}
}
}
call.respond(TextContent(gson.toJson(when (queries) {
null -> result.single()
else -> result
}), ContentType.Application.Json, HttpStatusCode.OK))
TextContent(gson.toJson(when (queries) {
null -> result.single()
else -> result
}), ContentType.Application.Json, HttpStatusCode.OK)
}
}
}
call.respond(response)
}
get("/updates") {
pool.connection.use { connection ->
val queries = call.queries()
val random = ThreadLocalRandom.current()
val result = mutableListOf<World>()
connection.prepareStatement("SELECT * FROM World WHERE id = ?", TYPE_FORWARD_ONLY, CONCUR_READ_ONLY).use { statement ->
for (i in 1..(queries ?: 1)) {
statement.setInt(1, random.nextInt(DbRows) + 1)
statement.executeQuery().use { rs ->
while (rs.next()) {
result += World(rs.getInt("id"), rs.getInt("randomNumber"))
val t = run(databaseDispatcher) {
pool.connection.use { connection ->
val queries = call.queries()
val random = ThreadLocalRandom.current()
val result = mutableListOf<World>()
connection.prepareStatement("SELECT * FROM World WHERE id = ?", TYPE_FORWARD_ONLY, CONCUR_READ_ONLY).use { statement ->
for (i in 1..(queries ?: 1)) {
statement.setInt(1, random.nextInt(DbRows) + 1)
statement.executeQuery().use { rs ->
while (rs.next()) {
result += World(rs.getInt("id"), rs.getInt("randomNumber"))
}
}
}
}
}
}
result.forEach { it.randomNumber = random.nextInt(DbRows) + 1 }
result.forEach { it.randomNumber = random.nextInt(DbRows) + 1 }
connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?").use { updateStatement ->
for ((id, randomNumber) in result) {
updateStatement.setInt(1, randomNumber)
updateStatement.setInt(2, id)
connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?").use { updateStatement ->
for ((id, randomNumber) in result) {
updateStatement.setInt(1, randomNumber)
updateStatement.setInt(2, id)
updateStatement.executeUpdate()
updateStatement.executeUpdate()
}
}
}
call.respond(TextContent(gson.toJson(when (queries) {
null -> result.single()
else -> result
}), ContentType.Application.Json, HttpStatusCode.OK))
TextContent(gson.toJson(when (queries) {
null -> result.single()
else -> result
}), ContentType.Application.Json, HttpStatusCode.OK)
}
}
call.respond(t)
}
}
}.start(true)
@@ -115,6 +136,7 @@ private fun hikari(dbHost: String, a: String, b: String): DataSource {
config.addDataSourceProperty("prepStmtCacheSize", "250")
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048")
config.driverClassName = Driver::class.java.name
config.connectionTimeout = 10000
return HikariDataSource(config)
}
View
@@ -0,0 +1,63 @@
package org.jetbrains.ktor.benchmarks
import org.jetbrains.ktor.application.*
import org.jetbrains.ktor.http.*
import org.jetbrains.ktor.logging.*
import org.jetbrains.ktor.pipeline.*
import org.jetbrains.ktor.request.*
import org.jetbrains.ktor.util.*
import java.util.concurrent.atomic.*
// utility logging feature useful for debugging benchmark
internal class SamplingCallLogging(private val log: ApplicationLog) {
private val counter = AtomicLong()
var samplingFactor = 10000L
fun log(call: ApplicationCall) {
val v = counter.incrementAndGet()
if (v < 0) counter.set(0)
if (v % samplingFactor == 0L) {
logSuccess(call)
}
}
private fun logSuccess(call: ApplicationCall) {
val status = call.response.status() ?: "Unhandled"
when (status) {
HttpStatusCode.Found -> log.trace("$status: ${call.request.logInfo()} -> ${call.response.headers[HttpHeaders.Location]}")
else -> log.trace("$status: ${call.request.logInfo()}")
}
}
private fun ApplicationRequest.logInfo() = "${httpMethod.value} - ${path()}"
companion object : ApplicationFeature<Application, SamplingCallLogging, SamplingCallLogging> {
override val key = AttributeKey<SamplingCallLogging>("SamplingCallLogging")
override fun install(pipeline: Application, configure: SamplingCallLogging.() -> Unit): SamplingCallLogging {
pipeline.environment.monitor.logEvents()
val feature = SamplingCallLogging(pipeline.log)
configure(feature)
val loggingPhase = PipelinePhase("SLogging")
pipeline.phases.insertBefore(ApplicationCallPipeline.Infrastructure, loggingPhase)
pipeline.intercept(loggingPhase) { call ->
proceed()
feature.log(call)
}
return feature
}
private fun ApplicationMonitor.logEvents() {
applicationStarted += { it.log.trace("Application started: $it") }
applicationStopped += { it.log.trace("Application stopped: $it") }
applicationStarting += { it.log.trace("Application starting: $it") }
applicationStopping += { it.log.trace("Application stopping: $it") }
}
}
}
View
@@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="trace">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>
</configuration>
View
@@ -6,7 +6,7 @@ gem 'hanami-model', '~> 1.0'
gem 'mysql2'
gem 'rom-sql', git: 'https://github.com/rom-rb/rom-sql'
gem 'rom-sql'
group :production do
gem 'puma'
View
@@ -96,7 +96,7 @@ class Application < Hanami::Application
# Default format for responses that don't consider the request format
# Argument: A symbol representation of a mime type, defaults to :html
#
default_response_format :json
# default_response_format :json
# HTTP Body parsers
# Parse non GET responses body for a specific mime type
View
@@ -1,5 +1,6 @@
module Web::Views::HelloWorld
class Fortune
include Web::View
format :html
end
end
View
@@ -8,11 +8,11 @@ futures = "0.1"
tokio-proto = "0.1"
tokio-service = "0.1"
num_cpus = "1.2"
serde = "0.9"
serde_json = "0.9"
serde_derive = "0.9"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
mime = "0.2"
[dependencies.hyper]
git = "https://github.com/hyperium/hyper/"
rev = "030393d09987ef0fa1866d74b4bb1ab1e46905a3"
rev = "acd62cda446e4c647716a2d595342360dc24a080"
View
@@ -555,6 +555,9 @@ def exit_with_code(code):
##########################
normalPIDs = subprocess.check_output(['ps -o pid,ppid,comm -u $(whoami)'], shell=True)
if self.__is_port_bound(test.port):
time.sleep(60)
if self.__is_port_bound(test.port):
# We gave it our all
self.__write_intermediate_results(test.name, "port " + str(test.port) + " is not available before start")
View
@@ -38,37 +38,54 @@ void reap(int signum)
char command[256];
sprintf(command, "findChilds() { for child in $(ps --ppid $1 ho pid); do echo $child; findChilds $child; done } && findChilds %d", pid);
char *pids[256];
fp = popen(command, "r");
while(fgets(buf, sizeof(buf), fp) != 0)
{
Node *newNode = malloc(sizeof(Node));
newNode->str = malloc(strlen(buf)+1);
strcpy(newNode->str, buf);
newNode->next = NULL;
int count;
if(tail == NULL)
{
tail = newNode;
head = newNode;
}
else
do
{
count = 0;
char *pids[256];
fp = popen(command, "r");
while(fgets(buf, sizeof(buf), fp) != 0)
{
if(head->next == NULL)
Node *newNode = malloc(sizeof(Node));
newNode->str = malloc(strlen(buf)+1);
strcpy(newNode->str, buf);
newNode->next = NULL;
if(tail == NULL)
{
head->next = newNode;
tail = newNode;
head = newNode;
}
tail->next = newNode;
tail = newNode;
else
{
if(head->next == NULL)
{
head->next = newNode;
}
tail->next = newNode;
tail = newNode;
}
count ++;
}
}
Node *curr = head;
while(curr != NULL)
{
kill(atoi(curr->str), SIGKILL);
curr = curr->next;
Node *curr = head;
while(curr != NULL)
{
kill(atoi(curr->str), SIGKILL);
curr = curr->next;
}
}
// This may seem magical, but that command from above always results in two
// additionally PIDs: one for `ps` and one for `sh`. Therefore, all of the
// lineage of this TFBReaper have been successfully killed once there are
// only two PIDs counted in the loop.
// This loop is necessary for edge cases where there is a master->slave
// lineage and TFBReaper kills a slave first, which is observed and fixed
// by the master by spawning a NEW slave in the original's place, and then
// killing the master (thus orphaning the newly spawned slave, but that PID
// is not in our master list).
while(count > 2);
exit(0);
}
View
@@ -41,6 +41,7 @@ datadir = /ssd/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
skip-name-resolve
lower_case_table_names = 1
character-set-server=utf8
@@ -52,7 +53,7 @@ collation-server=utf8_general_ci
#
# * Fine Tuning
#
key_buffer = 16M
key_buffer_size = 16M
max_allowed_packet = 16M
thread_stack = 256K
thread_cache_size = 128
View
@@ -2,7 +2,7 @@
fw_installed cutelyst && return 0
CUTELYST_VER=1.6.0-beta7
CUTELYST_VER=1.7.0
QT_VERSION_MM=56
QT_VERSION_FULL=562-trusty
CROOT=${IROOT}/cutelyst
View
@@ -2,7 +2,7 @@
fw_installed node && return 0
VERSION="7.10.0"
VERSION="8.0.0"
fw_get -O http://nodejs.org/dist/v$VERSION/node-v$VERSION-linux-x64.tar.gz
fw_untar node-v$VERSION-linux-x64.tar.gz