|
@@ -13,7 +13,7 @@ import 'package:yaml/yaml.dart' as yaml;
|
|
/// address and port for incoming connections is configurable via command line
|
|
/// address and port for incoming connections is configurable via command line
|
|
/// arguments, as is the number of database connections to be maintained in the
|
|
/// arguments, as is the number of database connections to be maintained in the
|
|
/// connection pool.
|
|
/// connection pool.
|
|
-main(List<String> args) {
|
|
|
|
|
|
+void main(List<String> args) {
|
|
var parser = new ArgParser();
|
|
var parser = new ArgParser();
|
|
parser.addOption('address', abbr: 'a', defaultsTo: '0.0.0.0');
|
|
parser.addOption('address', abbr: 'a', defaultsTo: '0.0.0.0');
|
|
parser.addOption('port', abbr: 'p', defaultsTo: '8080');
|
|
parser.addOption('port', abbr: 'p', defaultsTo: '8080');
|
|
@@ -22,17 +22,17 @@ main(List<String> args) {
|
|
var arguments = parser.parse(args);
|
|
var arguments = parser.parse(args);
|
|
var isolates = int.parse(arguments['isolates']);
|
|
var isolates = int.parse(arguments['isolates']);
|
|
var dbConnections = int.parse(arguments['dbconnections']) ~/ isolates;
|
|
var dbConnections = int.parse(arguments['dbconnections']) ~/ isolates;
|
|
- ServerSocket.bind(arguments['address'], int.parse(arguments['port']))
|
|
|
|
- .then((server) {
|
|
|
|
- var ref = server.reference;
|
|
|
|
- for (int i = 1; i < isolates; i++) {
|
|
|
|
- Isolate.spawn(startInIsolate, [ref, dbConnections]);
|
|
|
|
- }
|
|
|
|
- _startServer(server, dbConnections);
|
|
|
|
- });
|
|
|
|
|
|
+ ServerSocket.bind(arguments['address'], int.parse(arguments['port'])).then(
|
|
|
|
+ (server) {
|
|
|
|
+ var ref = server.reference;
|
|
|
|
+ for (int i = 1; i < isolates; i++) {
|
|
|
|
+ Isolate.spawn(startInIsolate, [ref, dbConnections]);
|
|
|
|
+ }
|
|
|
|
+ _startServer(server, dbConnections);
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
-void startInIsolate(args) {
|
|
|
|
|
|
+void startInIsolate(List args) {
|
|
var ref = args[0];
|
|
var ref = args[0];
|
|
var dbConnections = args[1];
|
|
var dbConnections = args[1];
|
|
ref.create().then((server) {
|
|
ref.create().then((server) {
|
|
@@ -48,7 +48,7 @@ class World {
|
|
|
|
|
|
World(this.id, this.randomnumber);
|
|
World(this.id, this.randomnumber);
|
|
|
|
|
|
- toJson() => { 'id': id, 'randomNumber': randomnumber };
|
|
|
|
|
|
+ toJson() => {'id': id, 'randomNumber': randomnumber};
|
|
}
|
|
}
|
|
|
|
|
|
/// The entity used in the fortunes test.
|
|
/// The entity used in the fortunes test.
|
|
@@ -58,7 +58,7 @@ class Fortune implements Comparable<Fortune> {
|
|
|
|
|
|
Fortune(this.id, this.message);
|
|
Fortune(this.id, this.message);
|
|
|
|
|
|
- compareTo(Fortune other) => message.compareTo(other.message);
|
|
|
|
|
|
+ int compareTo(Fortune other) => message.compareTo(other.message);
|
|
}
|
|
}
|
|
|
|
|
|
/// The number of rows in the world entity table.
|
|
/// The number of rows in the world entity table.
|
|
@@ -69,21 +69,20 @@ final _RANDOM = new Random();
|
|
|
|
|
|
/// The PostgreSQL connection pool used by all the tests that require database
|
|
/// The PostgreSQL connection pool used by all the tests that require database
|
|
/// connectivity.
|
|
/// connectivity.
|
|
-var _connectionPool;
|
|
|
|
|
|
+pgpool.Pool _connectionPool;
|
|
|
|
|
|
/// The mustache template which is rendered in the fortunes test.
|
|
/// The mustache template which is rendered in the fortunes test.
|
|
-var _fortunesTemplate;
|
|
|
|
|
|
+mustache.Template _fortunesTemplate;
|
|
|
|
|
|
/// Starts a benchmark server, which listens for connections from
|
|
/// Starts a benchmark server, which listens for connections from
|
|
/// '[address] : [port]' and maintains [dbConnections] connections to the
|
|
/// '[address] : [port]' and maintains [dbConnections] connections to the
|
|
/// database.
|
|
/// database.
|
|
-_startServer(serverSocket, dbConnections) {
|
|
|
|
|
|
+void _startServer(serverSocket, dbConnections) {
|
|
Future.wait([
|
|
Future.wait([
|
|
new File('postgresql.yaml').readAsString().then((config) {
|
|
new File('postgresql.yaml').readAsString().then((config) {
|
|
_connectionPool = new pgpool.Pool(
|
|
_connectionPool = new pgpool.Pool(
|
|
new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(),
|
|
new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(),
|
|
- min: dbConnections,
|
|
|
|
- max: dbConnections);
|
|
|
|
|
|
+ min: dbConnections, max: dbConnections);
|
|
return _connectionPool.start();
|
|
return _connectionPool.start();
|
|
}),
|
|
}),
|
|
new File('fortunes.mustache').readAsString().then((template) {
|
|
new File('fortunes.mustache').readAsString().then((template) {
|
|
@@ -124,12 +123,12 @@ _startServer(serverSocket, dbConnections) {
|
|
/// Returns the given [text] parsed as a base 10 integer. If the text is null
|
|
/// Returns the given [text] parsed as a base 10 integer. If the text is null
|
|
/// or is an otherwise invalid representation of a base 10 integer, zero is
|
|
/// or is an otherwise invalid representation of a base 10 integer, zero is
|
|
/// returned.
|
|
/// returned.
|
|
-_parseInt(text) =>
|
|
|
|
|
|
+int _parseInt(String text) =>
|
|
(text == null) ? 0 : int.parse(text, radix: 10, onError: ((_) => 0));
|
|
(text == null) ? 0 : int.parse(text, radix: 10, onError: ((_) => 0));
|
|
|
|
|
|
/// Completes the given [request] by writing the [response] with the given
|
|
/// Completes the given [request] by writing the [response] with the given
|
|
/// [statusCode] and [type].
|
|
/// [statusCode] and [type].
|
|
-_sendResponse(request, statusCode, [ type, response ]) {
|
|
|
|
|
|
+void _sendResponse(HttpRequest request, int statusCode, [type, response]) {
|
|
request.response.statusCode = statusCode;
|
|
request.response.statusCode = statusCode;
|
|
request.response.headers.date = new DateTime.now();
|
|
request.response.headers.date = new DateTime.now();
|
|
if (type != null) {
|
|
if (type != null) {
|
|
@@ -146,92 +145,95 @@ _sendResponse(request, statusCode, [ type, response ]) {
|
|
}
|
|
}
|
|
|
|
|
|
/// Completes the given [request] by writing the [response] as HTML.
|
|
/// Completes the given [request] by writing the [response] as HTML.
|
|
-_sendHtml(request, response) {
|
|
|
|
|
|
+void _sendHtml(HttpRequest request, String response) {
|
|
_sendResponse(request, HttpStatus.OK, ContentType.HTML, response);
|
|
_sendResponse(request, HttpStatus.OK, ContentType.HTML, response);
|
|
}
|
|
}
|
|
|
|
|
|
/// Completes the given [request] by writing the [response] as JSON.
|
|
/// Completes the given [request] by writing the [response] as JSON.
|
|
-_sendJson(request, response) {
|
|
|
|
|
|
+void _sendJson(HttpRequest request, Object response) {
|
|
_sendResponse(
|
|
_sendResponse(
|
|
request, HttpStatus.OK, ContentType.JSON, JSON.encode(response));
|
|
request, HttpStatus.OK, ContentType.JSON, JSON.encode(response));
|
|
}
|
|
}
|
|
|
|
|
|
/// Completes the given [request] by writing the [response] as plain text.
|
|
/// Completes the given [request] by writing the [response] as plain text.
|
|
-_sendText(request, response) {
|
|
|
|
|
|
+void _sendText(HttpRequest request, String response) {
|
|
_sendResponse(request, HttpStatus.OK, ContentType.TEXT, response);
|
|
_sendResponse(request, HttpStatus.OK, ContentType.TEXT, response);
|
|
}
|
|
}
|
|
|
|
|
|
/// Responds with the JSON test to the [request].
|
|
/// Responds with the JSON test to the [request].
|
|
-_jsonTest(request) {
|
|
|
|
- _sendJson(request, { 'message': 'Hello, World!' });
|
|
|
|
|
|
+void _jsonTest(HttpRequest request) {
|
|
|
|
+ _sendJson(request, {'message': 'Hello, World!'});
|
|
}
|
|
}
|
|
|
|
|
|
-_queryRandom() {
|
|
|
|
- return _connectionPool.connect()
|
|
|
|
- .then((connection) {
|
|
|
|
- return connection.query(
|
|
|
|
- 'SELECT id, randomnumber FROM world WHERE id = @id;',
|
|
|
|
- { 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 })
|
|
|
|
- //
|
|
|
|
- // The benchmark's constraints tell us there is exactly one row.
|
|
|
|
- //
|
|
|
|
- .single
|
|
|
|
- .then((row) => new World(row[0], row[1]))
|
|
|
|
- .whenComplete(() { connection.close(); });
|
|
|
|
- });
|
|
|
|
|
|
+Future<World> _queryRandom() {
|
|
|
|
+ return _connectionPool.connect().then((connection) {
|
|
|
|
+ return connection.query(
|
|
|
|
+ 'SELECT id, randomnumber FROM world WHERE id = @id;', {
|
|
|
|
+ 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1
|
|
|
|
+ })
|
|
|
|
+ //
|
|
|
|
+ // The benchmark's constraints tell us there is exactly one row.
|
|
|
|
+ //
|
|
|
|
+ .single.then((row) => new World(row[0], row[1])).whenComplete(() {
|
|
|
|
+ connection.close();
|
|
|
|
+ });
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
/// Responds with the database query test to the [request].
|
|
/// Responds with the database query test to the [request].
|
|
-_dbTest(request) {
|
|
|
|
|
|
+void _dbTest(HttpRequest request) {
|
|
_queryRandom().then((response) => _sendJson(request, response));
|
|
_queryRandom().then((response) => _sendJson(request, response));
|
|
}
|
|
}
|
|
|
|
|
|
/// Responds with the database queries test to the [request].
|
|
/// Responds with the database queries test to the [request].
|
|
-_queriesTest(request) {
|
|
|
|
|
|
+void _queriesTest(HttpRequest request) {
|
|
var queries = _parseInt(request.uri.queryParameters['queries']).clamp(1, 500);
|
|
var queries = _parseInt(request.uri.queryParameters['queries']).clamp(1, 500);
|
|
- Future.wait(new List.generate(queries,
|
|
|
|
- (_) => _queryRandom(),
|
|
|
|
- growable: false))
|
|
|
|
|
|
+ Future
|
|
|
|
+ .wait(new List.generate(queries, (_) => _queryRandom(), growable: false))
|
|
.then((response) => _sendJson(request, response));
|
|
.then((response) => _sendJson(request, response));
|
|
}
|
|
}
|
|
|
|
|
|
/// Responds with the fortunes test to the [request].
|
|
/// Responds with the fortunes test to the [request].
|
|
-_fortunesTest(request) {
|
|
|
|
|
|
+void _fortunesTest(HttpRequest request) {
|
|
_connectionPool.connect().then((connection) {
|
|
_connectionPool.connect().then((connection) {
|
|
- return connection.query('SELECT id, message FROM fortune;')
|
|
|
|
|
|
+ return connection
|
|
|
|
+ .query('SELECT id, message FROM fortune;')
|
|
.map((row) => new Fortune(row[0], row[1]))
|
|
.map((row) => new Fortune(row[0], row[1]))
|
|
.toList()
|
|
.toList()
|
|
- .whenComplete(() { connection.close(); });
|
|
|
|
|
|
+ .whenComplete(() {
|
|
|
|
+ connection.close();
|
|
|
|
+ });
|
|
}).then((fortunes) {
|
|
}).then((fortunes) {
|
|
fortunes.add(new Fortune(0, 'Additional fortune added at request time.'));
|
|
fortunes.add(new Fortune(0, 'Additional fortune added at request time.'));
|
|
fortunes.sort();
|
|
fortunes.sort();
|
|
_sendHtml(request, _fortunesTemplate.renderString({
|
|
_sendHtml(request, _fortunesTemplate.renderString({
|
|
- 'fortunes': fortunes.map((fortune) => {
|
|
|
|
- 'id': fortune.id, 'message': fortune.message
|
|
|
|
- }).toList()
|
|
|
|
|
|
+ 'fortunes': fortunes
|
|
|
|
+ .map((fortune) => {'id': fortune.id, 'message': fortune.message})
|
|
|
|
+ .toList()
|
|
}));
|
|
}));
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
/// Responds with the updates test to the [request].
|
|
/// Responds with the updates test to the [request].
|
|
-_updatesTest(request) {
|
|
|
|
|
|
+void _updatesTest(HttpRequest request) {
|
|
var queries = _parseInt(request.uri.queryParameters['queries']).clamp(1, 500);
|
|
var queries = _parseInt(request.uri.queryParameters['queries']).clamp(1, 500);
|
|
Future.wait(new List.generate(queries, (_) {
|
|
Future.wait(new List.generate(queries, (_) {
|
|
- return _queryRandom()
|
|
|
|
- .then((world) {
|
|
|
|
- world.randomnumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1;
|
|
|
|
- return _connectionPool.connect().then((connection) {
|
|
|
|
- return connection.execute(
|
|
|
|
|
|
+ return _queryRandom().then((world) {
|
|
|
|
+ world.randomnumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1;
|
|
|
|
+ return _connectionPool.connect().then((connection) {
|
|
|
|
+ return connection
|
|
|
|
+ .execute(
|
|
'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;',
|
|
'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;',
|
|
- { 'randomnumber': world.randomnumber, 'id': world.id })
|
|
|
|
- .whenComplete(() { connection.close(); });
|
|
|
|
- }).then((_) => world);
|
|
|
|
|
|
+ {'randomnumber': world.randomnumber, 'id': world.id})
|
|
|
|
+ .whenComplete(() {
|
|
|
|
+ connection.close();
|
|
});
|
|
});
|
|
- }, growable: false))
|
|
|
|
- .then((worlds) => _sendJson(request, worlds));
|
|
|
|
|
|
+ }).then((_) => world);
|
|
|
|
+ });
|
|
|
|
+ }, growable: false)).then((worlds) => _sendJson(request, worlds));
|
|
}
|
|
}
|
|
|
|
|
|
/// Responds with the plaintext test to the [request].
|
|
/// Responds with the plaintext test to the [request].
|
|
-_plaintextTest(request) {
|
|
|
|
|
|
+void _plaintextTest(HttpRequest request) {
|
|
_sendText(request, 'Hello, World!');
|
|
_sendText(request, 'Hello, World!');
|
|
}
|
|
}
|