Skip to content

Commit

Permalink
Merge pull request #1149 from donovanmuller/master
Browse files Browse the repository at this point in the history
Added missing tests, new configuration with HikariCP and bumped Play version
  • Loading branch information
msmith-techempower committed Oct 29, 2014
2 parents 2f83079 + 66e1a07 commit 57de4cb
Show file tree
Hide file tree
Showing 33 changed files with 781 additions and 37 deletions.
29 changes: 27 additions & 2 deletions frameworks/Java/play2-java/benchmark_config
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,33 @@
"versus": "netty",
"port": "9000",
"db_url": "/db",
"query_url": "/queries?queries="
"query_url": "/queries?queries=",
"fortune_url": "/fortunes",
"update_url": "/update?queries=",
"plaintext_url": "/plaintext"
},
"java-jpa-hikaricp": {
"display_name": "play2-java-jpa-hikaricp",
"setup_file": "setup_java_jpa_hikaricp",
"framework": "play2",
"language": "Java",
"orm": "Full",
"os": "Linux",
"database": "MySQL",
"approach": "Realistic",
"classification": "Fullstack",
"platform": "Netty",
"webserver": "None",
"database_os": "Linux",
"notes": "",
"versus": "netty",
"port": "9000",
"db_url": "/db",
"query_url": "/queries?queries=",
"fortune_url": "/fortunes",
"update_url": "/update?queries=",
"plaintext_url": "/plaintext"
}
}
]
}
}
22 changes: 12 additions & 10 deletions frameworks/Java/play2-java/generate_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
# Format is: (language, orm, (opsys, ...), (test, ...))
# See the dir_name logic below to see the directory name for each test application.
configurations = [
('Java', None, ['Linux'], ['json']),
('Java', 'Ebean', ['Linux'], ['db', 'query']),
('Java', 'JPA', ['Linux'], ['db', 'query']),
('Scala', None, ['Linux'], ['json']),
('Scala', 'Anorm', ['Linux', 'Windows'], ['db', 'query', 'fortune', 'update']),
('Scala', 'Slick', ['Linux'], ['db', 'query', 'fortune', 'update']),
('Java', None, ['Linux'], ['json']),
('Java', 'Ebean', ['Linux'], ['db', 'query']),
('Java', 'JPA', ['Linux'], ['db', 'query', 'fortune', 'update', 'plaintext']),
('Java', 'JPA HikariCP', ['Linux'], ['db', 'query', 'fortune', 'update', 'plaintext']),
('Scala', None, ['Linux'], ['json']),
('Scala', 'Anorm', ['Linux', 'Windows'], ['db', 'query', 'fortune', 'update']),
('Scala', 'Slick', ['Linux'], ['db', 'query', 'fortune', 'update']),
]

# All play2 test applications must use the same URLs.
Expand All @@ -24,6 +25,7 @@
'query': '/queries?queries=',
'fortune': '/fortunes',
'update': '/update?queries=',
'plaintext': '/plaintext',
}

langs = {
Expand All @@ -41,8 +43,8 @@ def frameworksPath():
lang_test_configs[lang] = collections.OrderedDict()

for lang, orm, opsyses, tests in configurations:
dir_name = 'play2-' + lang.lower() + (('-'+orm.lower()) if orm else '')
setup_name = 'setup_' + lang.lower() + (('_'+orm.lower()) if orm else '')
dir_name = 'play2-' + lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '')
setup_name = 'setup_' + lang.lower() + (('_'+orm.replace(' ', '_').lower()) if orm else '')

setup_path = os.path.join(pathForLang(lang), setup_name+'.py')
print 'Generating', setup_path
Expand All @@ -57,9 +59,9 @@ def frameworksPath():

for opsys in opsyses:
if len(opsyses) == 1:
test_name = lang.lower() + (('-'+orm.lower()) if orm else '')
test_name = lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '')
else:
test_name = lang.lower() + (('-'+orm.lower()) if orm else '') + '-'+opsys.lower()
test_name = lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '') + '-'+opsys.lower()
test_config_json = collections.OrderedDict([
('display_name', 'play2-'+test_name),
('setup_file', setup_name),
Expand Down
29 changes: 29 additions & 0 deletions frameworks/Java/play2-java/play2-java-jpa-hikaricp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
logs
project/project
project/target
target
tmp
.history
dist

# Ignore all dotfiles...
.*
# except for .gitignore
!.gitignore

# Ignore Play! working directory #
db
eclipse
lib
log
logs
modules
precompiled
project/project
project/target
target
tmp
test-result
server.pid
*.iml
*.eml
40 changes: 40 additions & 0 deletions frameworks/Java/play2-java/play2-java-jpa-hikaricp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#Play Benchmarking Test

This is the Play portion of a [benchmarking test suite](../) comparing a variety of web development platforms.

### JSON Encoding Test

* [JSON test controller](app/controllers/Application.java)

### Data-Store/Database Mapping Test

* [Database test controller](app/controllers/Application.java)
* [Database World test model](app/models/World.java)
* [Database Fortune test model](app/models/Fortune.java)

### Plain Text Test

* [Plain text test controller](app/controllers/Application.java)

## Infrastructure Software Versions
The tests were run with:

* [Java OpenJDK 1.7](http://openjdk.java.net/)
* [Play 2.3.6](http://http://www.playframework.com/)

## Test URLs
### JSON Encoding Test

* http://localhost/json

### Data-Store/Database Mapping Test

* http://localhost/db
* http://localhost/queries?queries=10
* http://localhost/fortunes
* http://localhost/update?queries=10

### Plain Text Test

* http://localhost/plaintext

Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package controllers;

import akka.dispatch.ExecutionContexts;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import models.Fortune;
import models.World;
import play.*;
import play.core.NamedThreadFactory;
import play.libs.F;
import play.libs.Json;
import play.mvc.*;

import scala.concurrent.ExecutionContext;
import utils.Predicate;
import utils.Predicated;
import views.html.*;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Application extends Controller {

private static final int MAX_QUERIES_PER_REQUEST = 20;
private static final int TEST_DATABASE_ROWS = 10000;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

private static final int partitionCount = Play.application().configuration().getInt("db.default.partitionCount");
private static final int maxConnections =
partitionCount * Play.application().configuration().getInt("db.default.maxConnectionsPerPartition");
private static final int minConnections =
partitionCount * Play.application().configuration().getInt("db.default.minConnectionsPerPartition");

private static final ThreadPoolExecutor tpe = new ThreadPoolExecutor(minConnections, maxConnections,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
new NamedThreadFactory("dbEc"));
private static final ExecutionContext dbEc = ExecutionContexts.fromExecutorService(tpe);

public static Result json() {
final ObjectNode result = OBJECT_MAPPER.createObjectNode();
result.put("message", "Hello World!");
return ok(result);
}

// If the thread-pool used by the database grows too large then our server
// is probably struggling, and we should start dropping requests. Set
// the max size of our queue something above the number of concurrent
// connections that we need to handle.
public static class IsDbAvailable implements Predicate {
@Override
public boolean condition() {
return tpe.getQueue().size() <= 1024;
}
}

@Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
public static F.Promise<Result> db() {
return getRandomWorlds(1).map(new F.Function<List<World>, Result>() {
@Override
public Result apply(List<World> worlds) {
return ok(Json.toJson(worlds.get(0)));
}
});
}

@Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
public static F.Promise<Result> queries(final String queryCountString) {
return getRandomWorlds(queryCount(queryCountString)).map(new F.Function<List<World>, Result>() {
@Override
public Result apply(List<World> worlds) {
return ok(Json.toJson(worlds));
}
});
}

@Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
public static F.Promise<Result> fortunes() {
return F.Promise.promise(new F.Function0<Result>() {

@Override
public Result apply() throws Throwable {
List<Fortune> fortunes = Fortune.findAll();
fortunes.add(new Fortune("Additional fortune added at request time."));
Collections.sort(fortunes, new Comparator<Fortune>() {
@Override
public int compare(Fortune f1, Fortune f2) {
return f1.message.compareTo(f2.message);
}
});
return ok(views.html.fortunes.render(fortunes));
}
}, dbEc);
}

@Predicated(predicate = IsDbAvailable.class, failed = SERVICE_UNAVAILABLE)
public static F.Promise<Result> update(final String queryCountString) {
return getRandomWorlds(queryCount(queryCountString)).map(new F.Function<List<World>, Result>() {
@Override
public Result apply(List<World> worlds) throws Throwable {
Random random = ThreadLocalRandom.current();
for (World world : worlds) {
world.randomNumber = (long) (random.nextInt(10000) + 1);
}

worlds = World.save(worlds);
return ok(Json.toJson(worlds));
}
});
}

public static Result plainText() {
return ok("Hello, World!");
}

private static int queryCount(String queryCountString) {
int queryCount;
try {
queryCount = Integer.parseInt(queryCountString, 10);
} catch (NumberFormatException e) {
queryCount = 1;
}
if (queryCount < 1) {
queryCount = 1;
} else if (queryCount > 500) {
queryCount = 500;
}

return queryCount;
}

private static F.Promise<List<World>> getRandomWorlds(final int n) {
return F.Promise.promise(new F.Function0<List<World>>() {
@Override
public List<World> apply() throws Throwable {
Random random = ThreadLocalRandom.current();
List<World> worlds = new ArrayList<World>(n);
for (int i = 0; i < n; ++i) {
long randomId = random.nextInt(TEST_DATABASE_ROWS) + 1;
World world = World.findById(randomId);
worlds.add(world);
}
return worlds;
}
}, dbEc);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package models;

import play.db.jpa.JPA;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.criteria.CriteriaQuery;
import java.util.List;

@Entity
public class Fortune {

@Id
public Long id = 0L;

public String message;

public Fortune() {
}

public Fortune(String message) {
this.message = message;
}

public static List<Fortune> findAll() throws Throwable {
return JPA.withTransaction("default", true, new play.libs.F.Function0<List<Fortune>>() {
public List<Fortune> apply() {
CriteriaQuery<Fortune> criteria = JPA.em().getCriteriaBuilder().createQuery(Fortune.class);
criteria.select(criteria.from(Fortune.class));
return JPA.em().createQuery(criteria).getResultList();
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package models;

import play.db.jpa.JPA;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.List;

@Entity
public class World {

@Id
public Long id;

@Column(name = "randomNumber")
public Long randomNumber;

public static World findById(final Long id) throws Throwable {
return JPA.withTransaction("default", true, new play.libs.F.Function0<World>() {
public World apply() {
return JPA.em().find(World.class, id);
}
});
}

public static List<World> save(final List<World> worlds) throws Throwable {
for (final World world : worlds) {
JPA.withTransaction("default", false, new play.libs.F.Function0<World>() {
public World apply() {
return JPA.em().merge(world);
}
});
}

return worlds;
}
}
Loading

0 comments on commit 57de4cb

Please sign in to comment.