Browse Source

Add Redstone.dart framework

Luiz Mineo 11 years ago
parent
commit
150020367d

+ 1 - 0
dart-redstone/.gitignore

@@ -0,0 +1 @@
+packages/*

+ 63 - 0
dart-redstone/README.md

@@ -0,0 +1,63 @@
+# Redstone.dart Framework Benchmarking Test
+
+This test adds [Redstone.dart](http://redstonedart.org), a microframework for Dart, to the [benchmarking test suite](../). The test is based on the Dart Benchmarking Test.
+
+## Versions
+
+* [Dart SDK version >=1.3.0](https://launchpad.net/~hachre/+archive/dart)
+* [Dart args version 0.10.0+2](http://pub.dartlang.org/packages/args)
+* [Dart crypto version 0.9.0](http://pub.dartlang.org/packages/crypto)
+* [Dart mustache version 0.1.8](http://pub.dartlang.org/packages/mustache)
+* [Dart mongo_dart version 0.1.42](http://pub.dartlang.org/packages/mongo_dart)
+* [Dart postgresql version 0.2.13](http://pub.dartlang.org/packages/postgresql)
+* [Dart redstone version 0.5.8+1](http://pub.dartlang.org/packages/redstone)
+* [Dart yaml version 0.9.0](http://pub.dartlang.org/packages/yaml)
+* [Dart connection_pool version 0.1.0+2](http://pub.dartlang.org/packages/connection_pool)
+
+## Test URLs
+
+### Common
+
+#### JSON Encoding Test
+http://localhost:8080/json
+
+#### Plaintext Test
+http://localhost:8080/plaintext
+
+
+### PostgreSQL
+
+#### Data-Store/Database Mapping Test
+http://localhost:8080/pg/db
+
+#### Variable Query Test
+http://localhost:8080/pg/queries?queries=2
+
+#### Fortunes Test
+http://localhost:8080/pg/fortunes
+
+#### Data-Store/Database Update Test
+http://localhost:8080/pg/updates
+
+#### Variable Update Test
+http://localhost:8080/pg/updates?queries=2
+
+
+### MongoDB
+
+#### Data-Store/Database Mapping Test
+http://localhost:8080/mongo/db
+
+#### Variable Query Test
+http://localhost:8080/mongo/queries?queries=2
+
+#### Fortunes Test
+http://localhost:8080/mongo/fortunes
+
+#### Data-Store/Database Update Test
+http://localhost:8080/mongo/updates
+
+#### Variable Update Test
+http://localhost:8080/mongo/updates?queries=2
+
+

+ 0 - 0
dart-redstone/__init__.py


+ 49 - 0
dart-redstone/benchmark_config

@@ -0,0 +1,49 @@
+{
+  "framework": "redstone",
+  "tests": [{
+    "postgresql-raw": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/pg/db",
+      "query_url": "/pg/queries?queries=",
+      "fortune_url": "/pg/fortunes",
+      "update_url": "/pg/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "Postgres",
+      "framework": "redstone",
+      "language": "Dart",
+      "orm": "Raw",
+      "platform": "Dart",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "redstone",
+      "notes": "",
+      "versus": "dart"
+    },
+    "mongodb-raw": {
+      "setup_file": "setup",
+      "db_url": "/mongo/db",
+      "query_url": "/mongo/queries?queries=",
+      "fortune_url": "/mongo/fortunes",
+      "update_url": "/mongo/updates?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MongoDB",
+      "framework": "redstone",
+      "language": "Dart",
+      "orm": "Raw",
+      "platform": "Dart",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "redstone",
+      "notes": "",
+      "versus": "dart"
+    }
+  }]
+}

+ 20 - 0
dart-redstone/fortunes.mustache

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Fortunes</title>
+  </head>
+  <body>
+    <table>
+      <tr>
+        <th>id</th>
+        <th>message</th>
+      </tr>
+      {{#fortunes}}
+      <tr>
+        <td>{{id}}</td>
+        <td>{{message}}</td>
+      </tr>
+      {{/fortunes}}
+    </table>
+  </body>
+</html>

+ 3 - 0
dart-redstone/install.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+fw_depends dart nginx

+ 2 - 0
dart-redstone/mongodb.yaml

@@ -0,0 +1,2 @@
+host: localhost
+database: hello_world

+ 5 - 0
dart-redstone/postgresql.yaml

@@ -0,0 +1,5 @@
+host: tfbdata
+port: 5432
+user: benchmarkdbuser
+password: benchmarkdbpass
+database: hello_world

+ 15 - 0
dart-redstone/pubspec.yaml

@@ -0,0 +1,15 @@
+name: DartRedstoneBenchmark
+description: A benchmark of Redstone.dart, a server-side microframework for Dart
+environment:
+  sdk: ">=1.3.0 <2.0.0"
+dependencies:
+  args: 0.10.0+2
+  crypto: 0.9.0
+  mongo_dart: 0.1.42
+  mustache: 0.1.8
+  postgresql: 0.2.13
+  redstone: 0.5.8+1
+  redstone_mapper: 0.1.2
+  redstone_mapper_mongo: 0.1.1+1
+  redstone_mapper_pg: 0.1.0
+  yaml: 0.9.0

+ 251 - 0
dart-redstone/server.dart

@@ -0,0 +1,251 @@
+import "dart:core";
+import "dart:io";
+import 'dart:async' show Future;
+import 'dart:math' show Random;
+import "package:redstone/server.dart" as app;
+import "package:redstone_mapper/mapper.dart";
+import "package:redstone_mapper/plugin.dart";
+import "package:redstone_mapper_mongo/manager.dart";
+import "package:redstone_mapper_pg/manager.dart";
+import "package:postgresql/postgresql.dart" as pg;
+import "package:di/di.dart";
+import "package:args/args.dart";
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:mustache/mustache.dart' as mustache;
+
+const _WORLD_TABLE_SIZE = 10000;
+
+final _RANDOM = new Random();
+
+class Fortune implements Comparable<Fortune> {
+  
+  @Field()
+  int id;
+  
+  @Field()
+  String message;
+  
+  Fortune([this.id, this.message]);
+
+  compareTo(Fortune other) => message.compareTo(other.message);
+  
+}
+
+class World {
+  
+  @Field()
+  int id;
+
+  @Field(model: "randomnumber")
+  int randomNumber;
+
+}
+
+class MongoFortune implements Comparable<Fortune> {
+  
+  @Field(model: "_id")
+  int id;
+  
+  @Field()
+  String message;
+  
+  MongoFortune([this.id, this.message]);
+
+  compareTo(Fortune other) => message.compareTo(other.message);
+  
+}
+
+class MongoWorld {
+  
+  @Field(model: "_id")
+  int id;
+
+  @Field()
+  int randomNumber;
+
+}
+
+///Handle PostgreSql connections
[email protected](r'/pg/.+')
+pgSqlManager(PostgreSqlManager pgSql) {
+  pgSql.getConnection().then((conn) {
+    app.request.attributes["dbConn"] = conn;
+    app.chain.next(() {
+      pgSql.closeConnection(conn, error: app.chain.error);
+    });
+  });
+}
+
+///Handle MongoDb connections
[email protected](r'/mongo/.+')
+mongoDbManager(MongoDbManager mongoDb) {
+  mongoDb.getConnection().then((conn) {
+    app.request.attributes["dbConn"] = conn;
+    app.chain.next(() {
+      mongoDb.closeConnection(conn, error: app.chain.error);
+    });
+  });
+}
+
+///JSON test
[email protected]("/json")
+getJson() => {"message": "Hello, World!"};
+
+///PlainText test
[email protected]("/plaintext")
+getPlainText() => "Hello, World!";
+
+///PostgreSql tests
[email protected]("/pg")
+@Encode()
+class PgTests {
+  
+  static const worldQuery = 'SELECT id, randomnumber FROM world WHERE id = @id;';
+  static const worldUpdt = 'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;';
+  
+  static const fortuneQuery = 'SELECT id, message FROM fortune;';
+  
+  PostgreSql get pgSql => app.request.attributes["dbConn"];
+  
+  @app.Route("/db")
+  Future<World> queryTest() {
+    var params = { 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 };
+    return pgSql.query(worldQuery, World, params).then((list) => list[0]);
+  }
+
+  @app.Route("/queries")
+  Future<List<World>> queriesTest() {
+    var queries = _parseQueriesParam(app.request.queryParams.queries);
+    return Future.wait(new List.generate(queries, (_) => queryTest()));
+  } 
+  
+  @app.Route("/updates")
+  Future<List<World>> updateTest() {
+    var queries = _parseQueriesParam(app.request.queryParams.queries);
+    return Future.wait(new List.generate(queries, (_) => queryTest().then((world) {
+      world.randomNumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1;
+      return pgSql.execute(worldUpdt, world).then((_) => world);
+    })));
+  }
+  
+  @app.Route("/fortunes", responseType: "text/html")
+  Future<String> fortunesTest(@app.Inject() mustache.Template template) {
+    return pgSql.query(fortuneQuery, Fortune).then((values) {
+      values
+          ..add(new Fortune(0, 'Additional fortune added at request time.'))
+          ..sort();
+      
+      return template.renderString({
+        "fortunes": encode(values)
+      });
+    });
+  }
+  
+}
+
+///MongoDb tests
[email protected]("/mongo")
+@Encode()
+class MongoTests {
+  
+  static const worldCollection = "World";
+  static const fortuneCollection = "Fortune";
+  
+  MongoDb get mongoDb => app.request.attributes["dbConn"];
+  
+  @app.Route("/db")
+  Future<MongoWorld> queryTest() {
+    return mongoDb.findOne(worldCollection, MongoWorld, {
+      "_id": _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1
+    });
+  }
+  
+  @app.Route("/queries")
+  Future<List<MongoWorld>> queriesTest() {
+    var queries = _parseQueriesParam(app.request.queryParams.queries);
+    return Future.wait(new List.generate(queries, (_) => queryTest()));
+  }
+  
+  @app.Route("/updates")
+  Future<List<MongoWorld>> updateTest() {
+    var queries = _parseQueriesParam(app.request.queryParams.queries);
+    return Future.wait(new List.generate(queries, (_) => queryTest().then((world) {
+      world.randomNumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1;
+      return mongoDb.update(worldCollection, { "_id": world.id }, world)
+          .then((_) => world);
+    })));
+  }
+  
+  @app.Route("/fortunes", responseType: "text/html")
+  Future<String> fortunesTest(@app.Inject() mustache.Template template) {
+    return mongoDb.find(fortuneCollection, MongoFortune).then((values) {
+      values
+          ..add(new MongoFortune(0, 'Additional fortune added at request time.'))
+          ..sort();
+      
+      return template.renderString({
+        "fortunes": encode(values)
+      });
+    });
+  }
+  
+}
+
+main(List<String> args) {
+  var parser = new ArgParser();
+  parser.addOption('address', abbr: 'a', defaultsTo: '0.0.0.0');
+  parser.addOption('port', abbr: 'p', defaultsTo: '8080');
+  parser.addOption('dbconnections', abbr: 'd', defaultsTo: '256');
+  
+  var arguments = parser.parse(args);
+  var dbConnections = int.parse(arguments["dbconnections"]);
+  
+  MongoDbManager mongoDbManager;
+  PostgreSqlManager pgSqlManager;
+  mustache.Template fortunesTemplate;
+  
+  Future.wait([
+     
+    //load PostgreSql configuration
+    new File("postgresql.yaml").readAsString().then((config){
+      pgSqlManager = new PostgreSqlManager(
+          new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(),
+          min: dbConnections,
+          max: dbConnections);
+    }),
+    
+    //load MongoDb configuration
+    new File("mongodb.yaml").readAsString().then((config) {
+      var mongoConfig = yaml.loadYaml(config);
+      mongoDbManager = new MongoDbManager(
+          "mongodb://${mongoConfig["host"]}/${mongoConfig["database"]}", 
+          poolSize: dbConnections);
+    }),
+    
+    //load fortunes mustache template
+    new File('fortunes.mustache').readAsString().then((template) {
+      fortunesTemplate = mustache.parse(template);
+    })
+    
+  ]).then((_) {
+    
+    //app.setupConsoleLog();
+    
+    //install module for dependency injection
+    app.addModule(new Module()
+                      ..bind(MongoDbManager, toValue: mongoDbManager)
+                      ..bind(PostgreSqlManager, toValue: pgSqlManager)
+                      ..bind(mustache.Template, toValue: fortunesTemplate));
+    
+    //initialize mapper plugin
+    app.addPlugin(getMapperPlugin());
+    
+    //start the server
+    app.start(address: arguments["address"], port: int.parse(arguments["port"]));
+    
+  });
+}
+
+_parseQueriesParam(param) {
+  return param.isEmpty ? 1 : int.parse(param, radix: 10, onError: (_) => 1).clamp(1, 500);
+}

+ 75 - 0
dart-redstone/setup.py

@@ -0,0 +1,75 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args, logfile, errfile):
+  setup_util.replace_text('dart-redstone/postgresql.yaml', 'host: .*', 'host: ' + args.database_host)
+  setup_util.replace_text('dart-redstone/mongodb.yaml', 'host: .*', 'host: ' + args.database_host)
+  try:
+    #
+    # install dart dependencies
+    #
+    subprocess.check_call('pub upgrade', shell=True, cwd='dart-redstone', stderr=errfile, stdout=logfile)
+    #
+    # start dart servers
+    #
+    for port in range(9001, 9001 + args.max_threads):
+      subprocess.Popen('dart server.dart -a 127.0.0.1 -p ' + str(port) + ' -d ' + str(args.max_concurrency / args.max_threads), shell=True, cwd='dart-redstone', stderr=errfile, stdout=logfile)
+    #
+    # create nginx configuration
+    #
+    conf = []
+    conf.append('worker_processes ' + str(args.max_threads) + ';')
+    conf.append('error_log /dev/null error;')
+    conf.append('events {')
+    conf.append('    worker_connections 1024;')
+    conf.append('}')
+    conf.append('http {')
+    conf.append('    access_log off;')
+    conf.append('    include /usr/local/nginx/conf/mime.types;')
+    conf.append('    default_type application/octet-stream;')
+    conf.append('    sendfile on;')
+    conf.append('    upstream dart_cluster {')
+    for port in range(9001, 9001 + args.max_threads):
+      conf.append('        server 127.0.0.1:' + str(port) + ';')
+    conf.append('        keepalive ' + str(args.max_concurrency / args.max_threads) + ';')
+    conf.append('    }')
+    conf.append('    server {')
+    conf.append('        listen 8080;')
+    conf.append('        location / {')
+    conf.append('            proxy_pass http://dart_cluster;')
+    conf.append('            proxy_http_version 1.1;')
+    conf.append('            proxy_set_header Connection "";')
+    conf.append('        }')
+    conf.append('    }')
+    conf.append('}')
+    #
+    # write nginx configuration to disk
+    #
+    with open('dart-redstone/nginx.conf', 'w') as f:
+      f.write('\n'.join(conf))
+    #
+    # start nginx
+    #
+    subprocess.Popen('sudo /usr/local/nginx/sbin/nginx -c `pwd`/nginx.conf', shell=True, cwd='dart-redstone', stderr=errfile, stdout=logfile);
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop(logfile, errfile):
+  #
+  # stop nginx
+  #
+  subprocess.check_call('sudo /usr/local/nginx/sbin/nginx -c `pwd`/nginx.conf -s stop', shell=True, cwd='dart-redstone', stderr=errfile, stdout=logfile)
+  os.remove('dart-redstone/nginx.conf')
+  #
+  # stop dart servers
+  #
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'dart' in line and 'run-tests' not in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 15)
+  return 0