Procházet zdrojové kódy

Rewrite vibe.d benchmark test.

- Fix all errors
- Implement all tests (updates/fortunes)
- Use the web framework instead of just low-level HTTP router functionality
- Use JSON/BSON serialization instead of manual creation of DOM objects
- Remove database creation code
- Prepares for adding additional tests using other databases
Sönke Ludwig před 9 roky
rodič
revize
421d7e5dc5

+ 4 - 2
frameworks/D/vibed/benchmark_config.json

@@ -7,18 +7,20 @@
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "plaintext_url": "/plaintext",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates?queries=",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
       "database": "MongoDB",
       "framework": "vibed",
       "language": "D",
-      "orm": "Raw",
+      "orm": "Micro",
       "platform": "D",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "Vibe.D",
+      "display_name": "vibe.d",
       "notes": "",
       "versus": "vibed"
     }

+ 12 - 5
frameworks/D/vibed/dub.json

@@ -2,9 +2,16 @@
   "name": "fwb",
   "description": "A simple vibe.d server application.",
   "copyright": "Copyright © 2015, jin",
-  "authors": ["jin"],
-  "dependencies": {
-    "vibe-d": "~>0.7.19"
-  },
-  "versions": ["VibeDefaultMain"]
+  "authors": ["jin", "Sönke Ludwig"],
+  "dependencies": { "vibe-d": "~>0.7.26" },
+  "versions": ["VibeDefaultMain"],
+  "targetType": "executable",
+  "sourcePaths": [],
+  
+  "configurations": [
+  	{
+  		"name": "mongodb",
+  		"mainSourceFile": "source/mongodb.d"
+  	}
+  ]
 }

+ 10 - 10
frameworks/D/vibed/dub.selections.json

@@ -1,11 +1,11 @@
 {
-  "fileVersion": 1,
-  "versions": {
-    "memutils": "0.3.5",
-    "vibe-d": "0.7.23",
-    "libevent": "2.0.1+2.0.16",
-    "openssl": "1.1.4+1.0.1g",
-    "libev": "5.0.0+4.04",
-    "libasync": "0.7.1"
-  }
-}
+	"fileVersion": 1,
+	"versions": {
+		"memutils": "0.4.3",
+		"vibe-d": "0.7.26",
+		"libevent": "2.0.1+2.0.16",
+		"openssl": "1.1.4+1.0.1g",
+		"libasync": "0.7.5",
+		"libev": "5.0.0+4.04"
+	}
+}

+ 0 - 102
frameworks/D/vibed/source/app.d

@@ -1,102 +0,0 @@
-import vibe.appmain;
-import vibe.d;
-import std.random;
-
-const worldSize = 10000;
-const fortunesSize = 100;
-const mongoUrl = "mongodb://127.0.0.1/";
-
-MongoClient mongo;
-MongoCollection worldCollection;
-MongoCollection fortunesCollection;
-
-shared static this()
-{
-  mongo = connectMongoDB( mongoUrl );
-  worldCollection = mongo.getCollection( "hello_world.World" );
-  fortunesCollection = mongo.getCollection( "hello_world.Fortunes" );
-
-  auto router = new URLRouter;
-  router.get("/plaintext", &plaintext);
-  router.get("/json", &json);
-  router.get("/db", &db);
-  router.get("/queries", &queries);
-  router.get("/generate-world", &generateWorld);
-  router.get("/generate-fortunes", &generateFortunes);
-  router.get("/", staticTemplate!"index.dt");
-
-  auto settings = new HTTPServerSettings;
-  settings.port = 8080;
-
-  listenHTTP(settings, router);
-}
-
-void json(HTTPServerRequest req, HTTPServerResponse res)
-{
-  auto helloWorld  = Json([
-    "message" : *new Json( "Hello, World!" )
-  ]);
-  res.writeJsonBody( helloWorld );
-}
-
-void generateWorld(HTTPServerRequest req, HTTPServerResponse res)
-{
-  try {
-    worldCollection.drop();
-  } catch( Exception error ) {}
-  for( auto i = 0 ; i < worldSize ; ++i ) {
-    worldCollection.insert([
-      "_id": i + 1,
-      "randomNumber": uniform( 0 , worldSize )
-    ]);
-  }
-  res.writeBody( "Generated" );
-}
-
-void generateFortunes(HTTPServerRequest req, HTTPServerResponse res)
-{
-  try {
-    fortunesCollection.drop();
-  } catch( Exception error ) {}
-  for( uint i = 0 ; i < worldSize ; ++i ) {
-    fortunesCollection.insert([
-      "_id": new Bson( i + 1 ),
-      "message": new Bson( to!string( uniform( 0 , fortunesSize ) ) )
-    ]);
-  }
-  res.writeBody( "Generated" );
-}
-
-void db(HTTPServerRequest req, HTTPServerResponse res)
-{
-  auto data = worldCollection.findOne([
-    "_id": uniform( 1 , worldSize + 1 )
-  ]); 
-  res.writeJsonBody( data );
-}
-
-void queries(HTTPServerRequest req, HTTPServerResponse res)
-{
-  auto count = 1;
-  try {
-    count = to!uint( req.query["queries"] );
-    if( !count ) {
-      count = 1;
-    } else if( count > 500 ) {
-      count = 500;
-    }
-  } catch( Exception error ) { }
-  
-  auto data = new Bson[ count ];
-  for( uint i = 0 ; i < count ; ++i ) {
-    data[i] = worldCollection.findOne([
-      "_id": uniform( 1 , worldSize + 1 )
-    ]);
-  }
-  res.writeJsonBody( data );
-}
-
-void plaintext(HTTPServerRequest req, HTTPServerResponse res)
-{
-  res.writeBody("Hello, World!");
-}

+ 160 - 0
frameworks/D/vibed/source/mongodb.d

@@ -0,0 +1,160 @@
+import vibe.db.mongo.mongo;
+import vibe.http.router;
+import vibe.http.server;
+import vibe.web.web;
+
+import std.conv : ConvException, to;
+import std.random : uniform;
+
+
+const worldSize = 10000;
+const fortunesSize = 100;
+
+
+shared static this()
+{
+	auto router = new URLRouter;
+	router.registerWebInterface(new WebInterface);
+
+	auto settings = new HTTPServerSettings;
+	settings.port = 8080;
+	listenHTTP(settings, router);
+}
+
+class WebInterface {
+	private {
+		MongoCollection _worldCollection;
+		MongoCollection _fortuneCollection;
+	}
+
+	this()
+	{
+		import std.process : environment;
+		auto db = connectMongoDB(environment["DBHOST"]);
+		_worldCollection = db.getCollection("hello_world.World");
+		_fortuneCollection = db.getCollection("hello_world.Fortune");
+	}
+
+	// GET /
+	void get()
+	{
+		render!"index.dt";
+	}
+
+	// GET /json
+	void getJson(HTTPServerResponse res)
+	{
+		// NOTE: the status and content type parameters are optional, but we need
+		// to specify them, because the default content type is "application/json; charset=UTF8"
+		res.writeJsonBody(Message("Hello, World!"), HTTPStatus.ok, "application/json");
+	}
+
+	// GET /db
+	void getDB(HTTPServerResponse res)
+	{
+		struct Q { int _id; }
+		auto query = Q(uniform(1, worldSize + 1));
+		auto w = WorldResponse(_worldCollection.findOne!World(query));
+		res.writeJsonBody(w, HTTPStatus.ok, "application/json");
+	}
+
+	// GET /queries?queries=...
+	void getQueries(HTTPServerResponse res, string queries)
+	{
+		import std.algorithm : min, max;
+
+		// Convert the "queries" parameter to int and ignore any conversion errors
+		// Note that you'd usually declare queries as int instead. However, the
+		// test required to gracefully handle errors here.
+		int count = 1;
+		try count = min(max(queries.to!int, 1), 500);
+		catch (ConvException) {}
+
+		// assemble the response array    
+		scope data = new WorldResponse[count];
+		foreach (ref w; data) {
+			static struct Q { int _id; }
+			auto query = Q(uniform(1, worldSize + 1));
+			w = WorldResponse(_worldCollection.findOne!World(query));
+		}
+
+		// write response as JSON
+		res.writeJsonBody(data, HTTPStatus.ok, "application/json");
+	}
+
+	// GET /fortunes
+	void getFortunes()
+	{
+		import std.algorithm : map, sort;
+
+		FortuneResponse[] data;
+		data = _fortuneCollection.find!Fortune().map!(f => FortuneResponse(f)).array;
+		data ~= FortuneResponse(Fortune(0, "Additional fortune added at request time."));
+		data.sort!((a, b) => a.message < b.message);
+		render!("fortunes.dt", data);
+	}
+
+	// GET /updates?queries=...
+	void getUpdates(HTTPServerResponse res, string queries)
+	{
+		import std.algorithm : min, max;
+
+		int count = 1;
+		try count = min(max(queries.to!int, 1), 500);
+		catch (ConvException e) {}
+
+		scope data = new WorldResponse[count];
+		foreach (ref w; data) {
+			static struct Q { int _id; }
+			auto query = Q(uniform(1, worldSize + 1));
+			w = WorldResponse(_worldCollection.findOne!World(query));
+
+			// update random number
+			w.randomNumber = uniform(1, worldSize+1);
+
+			// persist to DB
+			static struct US {
+				double randomNumber;
+			}
+			static struct U {
+				@name("$set") US set;
+			}
+			_worldCollection.update(query, U(US(w.randomNumber)));
+		}
+
+		// write response as JSON
+		res.writeJsonBody(data, HTTPStatus.ok, "application/json");
+	}
+
+	// GET /plaintext
+	void getPlaintext(HTTPServerResponse res)
+	{
+		res.writeBody("Hello, World!", HTTPStatus.ok, "text/plain");
+	}
+}
+
+struct Message {
+	string message;
+}
+
+struct World {
+	double _id;
+	double randomNumber;
+}
+
+struct Fortune {
+	double _id;
+	string message;
+}
+
+struct WorldResponse {
+	this(World w) { this.id = cast(int)w._id; this.randomNumber = cast(int)w.randomNumber; }
+	int id;
+	int randomNumber;
+}
+
+struct FortuneResponse {
+	this(Fortune f) { this.id = cast(int)f._id; this.message = f.message; }
+	int id;
+	string message;
+}

+ 15 - 0
frameworks/D/vibed/views/fortunes.dt

@@ -0,0 +1,15 @@
+extends layout
+
+block head
+	title Fortunes
+
+block body
+	table
+		tr
+			th id
+			th message
+		- foreach (f; data)
+			tr
+				td= f.id
+				td= f.message
+

+ 7 - 0
frameworks/D/vibed/views/layout.dt

@@ -0,0 +1,7 @@
+doctype html
+html
+	head
+		block head
+	body
+		block body
+