Browse Source

tornado refactor

- add pypy
- split py2 and py3
Dith3r 8 years ago
parent
commit
b1686804ec

+ 0 - 16
frameworks/Python/tornado/README.md

@@ -15,22 +15,6 @@ the [Python README](../).
 * [Mongodb](https://www.mongodb.org/) with [motor](http://motor.readthedocs.org/en/stable/)
 * [Mongodb](https://www.mongodb.org/) with [motor](http://motor.readthedocs.org/en/stable/)
 * [PostgreSQL](http://www.postgresql.org/) with [momoko](http://momoko.61924.nl/en/latest/)
 * [PostgreSQL](http://www.postgresql.org/) with [momoko](http://momoko.61924.nl/en/latest/)
 
 
-## Test Paths & Sources
-
-### Raw Database Tests
-
-* [Single Database Query](server.py): "/dbraw"
-* [Multiple Database Queries](server.py): "/queriesraw?queries=#"*
-
-### Tests
-
-* [JSON Serialization](server.py): "/json"
-* [Single Database Query](server.py): "/db"
-* [Multiple Database Queries](server.py): "/queries?queries=#"*
-* [Plaintext](server.py): "/plaintext"
-
-*Replace # with an actual number.
-
 ## Get Help
 ## Get Help
 
 
 ### Community
 ### Community

+ 39 - 9
frameworks/Python/tornado/benchmark_config.json

@@ -2,11 +2,13 @@
   "framework": "tornado",
   "framework": "tornado",
   "tests": [{
   "tests": [{
     "default": {
     "default": {
-      "setup_file": "setup",
+      "setup_file": "setup_py2",
       "json_url": "/json",
       "json_url": "/json",
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "query_url": "/queries?queries=",
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates?queries=",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Platform",
       "classification": "Platform",
@@ -19,14 +21,40 @@
       "webserver": "Tornado",
       "webserver": "Tornado",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
-      "display_name": "Tornado-raw",
+      "display_name": "Tornado-Py2-Mongo",
       "notes": "CPython 2.7",
       "notes": "CPython 2.7",
-      "versus": ""
+      "versus": "tornado"
+    },
+    "pypy": {
+      "setup_file": "setup_pypy",
+      "json_url": "/json",
+      "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": "None",
+      "language": "Python",
+      "flavor": "Pypy",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "Tornado",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Tornado-Pypy-Mongo",
+      "notes": "Pypy",
+      "versus": "tornado"
     },
     },
     "postgresql-raw": {
     "postgresql-raw": {
       "setup_file": "setup_pg",
       "setup_file": "setup_pg",
-      "db_url": "/dbraw",
-      "query_url": "/queriesraw?queries=",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "plaintext_url": "/plaintext",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Platform",
       "classification": "Platform",
@@ -39,9 +67,9 @@
       "webserver": "Tornado",
       "webserver": "Tornado",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
-      "display_name": "Tornado-raw",
+      "display_name": "Tornado-Py2-Pg",
       "notes": "CPython 2.7",
       "notes": "CPython 2.7",
-      "versus": ""
+      "versus": "tornado"
     },
     },
     "py3": {
     "py3": {
       "setup_file": "setup_py3",
       "setup_file": "setup_py3",
@@ -49,6 +77,8 @@
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "query_url": "/queries?queries=",
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates?queries=",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Platform",
       "classification": "Platform",
@@ -61,9 +91,9 @@
       "webserver": "Tornado",
       "webserver": "Tornado",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
-      "display_name": "Tornado-raw",
+      "display_name": "Tornado-Py3-Mongo",
       "notes": "CPython 3.4",
       "notes": "CPython 3.4",
-      "versus": ""
+      "versus": "tornado"
     }
     }
   }]
   }]
 }
 }

+ 42 - 0
frameworks/Python/tornado/commons.py

@@ -0,0 +1,42 @@
+import json
+import tornado.web
+
+
+def fortunes_sort(o1, o2):
+    return o1['message'] < o2['message']
+
+
+class BaseHandler(tornado.web.RequestHandler):
+    RANDOM_NUMBER = "randomNumber"
+    ID = "id"
+    QUERIES = "queries"
+
+    def compute_etag(self):
+        return None
+
+
+class PlainHandler(BaseHandler):
+
+    def set_default_headers(self):
+        self.set_header("Content-Type", 'text/plain')
+
+
+class JsonHandler(BaseHandler):
+
+    def set_default_headers(self):
+        self.set_header("Content-Type", "application/json; charset=UTF-8")
+
+
+class PlaintextHelloWorldHandler(PlainHandler):
+    HELLO_WORLD = b"Hello, World!"
+
+    def get(self):
+        self.finish(self.HELLO_WORLD)
+
+
+class JsonHelloWorldHandler(JsonHandler):
+    HELLO_WORLD = {"message": "Hello, World!"}
+
+    def get(self):
+        obj = json.dumps(self.HELLO_WORLD)
+        self.finish(obj)

+ 1 - 1
frameworks/Python/tornado/requirements.txt

@@ -1,3 +1,3 @@
 tornado==4.4.2
 tornado==4.4.2
-motor==0.6.2
+motor==1.1
 Momoko==2.2.3
 Momoko==2.2.3

+ 0 - 137
frameworks/Python/tornado/server.py

@@ -1,137 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import json
-from random import randint
-
-import momoko
-import motor
-import tornado.ioloop
-import tornado.web
-from tornado import gen
-import tornado.options
-from tornado.options import options
-import tornado.httpserver
-
-PY3 = False
-if sys.version_info[0] == 3:
-    PY3 = True
-    xrange = range
-
-tornado.options.define('port', default=8888, type=int, help="Server port")
-tornado.options.define('mongo', default='localhost', type=str, help="MongoDB host")
-tornado.options.define('postgres', default=None, type=str, help="PostgreSQL host")
-
-
-class BaseHandler(tornado.web.RequestHandler):
-    def compute_etag(self):
-        return None
-
-
-class JsonSerializeTestHandler(BaseHandler):
-    def get(self):
-        obj = {"message": "Hello, World!", }
-        self.write(obj)
-
-
-class PlaintextHandler(BaseHandler):
-    def get(self):
-        self.set_header('Content-Type', 'text/plain')
-        self.write(b"Hello, World!")
-
-
-class DBTestHandler(BaseHandler):
-    @gen.coroutine
-    def get(self):
-        world = yield db.World.find_one(randint(1, 10000))
-        # Get first postion on arguments, and so first postion in mongo return
-        world['id'] = int(world.pop('_id'))
-        world['randomNumber'] = int(world['randomNumber'])
-        response = json.dumps(world)
-        self.set_header("Content-Type", "application/json; charset=UTF-8")
-        self.write(response)
-
-
-class QueryTestHandler(BaseHandler):
-    @gen.coroutine
-    def get(self):
-        try:
-            queries = int(self.get_argument("queries"))
-        except Exception:
-            queries = 1
-        else:
-            if queries < 1:
-                queries = 1
-            elif queries > 500:
-                queries = 500
-
-        worlds = yield [db.World.find_one(randint(1, 10000))
-                        for _ in xrange(queries)]
-        for world in worlds:
-            # Get first postion on arguments, and so first postion in mongo return
-            world['id'] = int(world.pop('_id'))
-            world['randomNumber'] = int(world['randomNumber'])
-        response = json.dumps(worlds)
-        self.set_header("Content-Type", "application/json; charset=UTF-8")
-        self.write(response)
-
-
-class QueryPostgresRawTestHandler(BaseHandler):
-    @gen.coroutine
-    def get(self):
-        sql = "SELECT id, randomNumber FROM World WHERE id=%s"
-
-        random_id = randint(1, 10000)
-        cursor = yield self.application.db.execute(sql, (random_id,))
-        row = cursor.fetchone()
-        response = json.dumps({"id": row[0], "randomNumber": row[1]})
-
-        self.set_header("Content-Type", "application/json; charset=UTF-8")
-        self.write(response)
-
-
-class MultipleQueriesPostgresRawTestHandler(BaseHandler):
-    @gen.coroutine
-    def get(self):
-        queries = self.get_argument("queries", "1")
-        try:
-            queries = int(queries.strip())
-        except ValueError:
-            queries = 1
-
-        queries = min(max(1, queries), 500)
-
-        sql = "SELECT id, randomNumber FROM World WHERE id=%s"
-
-        cursors = yield [self.application.db.execute(sql, (randint(1, 10000),)) for _ in xrange(int(queries))]
-        rows = [cursor.fetchone() for cursor in cursors] 
-        worlds = [{"id": row[0], "randomNumber":row[1]} for row in rows]
-
-        response = json.dumps(worlds)
-        self.set_header("Content-Type", "application/json; charset=UTF-8")
-        self.write(response)
-
-application = tornado.web.Application([
-    (r"/json", JsonSerializeTestHandler),
-    (r"/plaintext", PlaintextHandler),
-    (r"/db", DBTestHandler),
-    (r"/queries", QueryTestHandler),
-    (r"/dbraw", QueryPostgresRawTestHandler),
-    (r"/queriesraw", MultipleQueriesPostgresRawTestHandler)
-])
-
-
-if __name__ == "__main__":
-    tornado.options.parse_command_line()
-    server = tornado.httpserver.HTTPServer(application)
-    server.bind(options.port)
-    server.start(0)
-
-    ioloop = tornado.ioloop.IOLoop.instance()
-    if options.postgres:
-        dsn = "user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world host=%s" % options.postgres
-        application.db = momoko.Pool(dsn, size=1, max_size=100)
-        ioloop.run_sync(application.db.connect)
-    else:
-        db = motor.MotorClient(options.mongo).hello_world
-    ioloop.start()

+ 77 - 0
frameworks/Python/tornado/server_pg.py

@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+import json
+from random import randint
+
+import momoko
+import tornado.ioloop
+import tornado.web
+from tornado import gen
+import tornado.options
+from tornado.options import options
+import tornado.httpserver
+from commons import JsonHandler, JsonHelloWorldHandler, PlaintextHelloWorldHandler, BaseHandler
+
+
+tornado.options.define('port', default=8888, type=int, help="Server port")
+tornado.options.define('postgres', default=None,
+                       type=str, help="PostgreSQL host")
+tornado.options.define('backlog', defualt=8192, type=int,
+                       help="Server backlog")
+
+
+class SingleQueryHandler(JsonHandler):
+    SQL = "SELECT id, randomNumber FROM World WHERE id=%s"
+
+    @gen.coroutine
+    def get(self):
+
+        random_id = randint(1, 10000)
+        cursor = yield db.execute(self.sql, (random_id,))
+        row = cursor.fetchone()
+        response = json.dumps({self.ID: row[0], self.RANDOM_NUMBER: row[1]})
+        self.finish(response)
+
+
+class MultipleQueriesHandler(JsonHandler):
+    SQL = "SELECT id, randomNumber FROM World WHERE id=%s"
+
+    @gen.coroutine
+    def get(self):
+        queries = self.get_argument(self.QUERIES, "1")
+        try:
+            queries = int(queries.strip())
+        except ValueError:
+            queries = 1
+
+        queries = min(max(1, queries), 500)
+        worlds = []
+
+        cursors = yield [db.execute(self.SQL, (randint(1, 10000),)) for _ in xrange(queries)]
+        for cursor in cursors:
+            row = cursor.fetchone()
+            worlds.append({self.ID: row[0], self.RANDOM_NUMBER: row[1]})
+
+        response = json.dumps(worlds)
+        self.finish(response)
+
+
+application = tornado.web.Application([
+    (r"/json", JsonHelloWorldHandler),
+    (r"/plaintext", PlaintextHelloWorldHandler),
+    (r"/db", SingleQueryHandler),
+    (r"/queries", MultipleQueriesHandler)
+],
+    template_path="templates"
+)
+
+if __name__ == "__main__":
+    tornado.options.parse_command_line()
+    server = tornado.httpserver.HTTPServer(application)
+    server.bind(options.port, backlog=options.backlog)
+    server.start(0)
+
+    ioloop = tornado.ioloop.IOLoop.instance()
+    dsn = "user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world host=%s" % options.postgres
+    db = momoko.Pool(dsn, size=100, max_size=200)
+    ioloop.run_sync(application.db.connect)
+    ioloop.start()

+ 115 - 0
frameworks/Python/tornado/server_py2.py

@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+
+import json
+import motor
+import tornado.ioloop
+import tornado.web
+import tornado.httpserver
+
+from random import randint
+from tornado import gen
+from tornado.options import options
+from commons import JsonHandler, JsonHelloWorldHandler, PlaintextHelloWorldHandler, BaseHandler, fortunes_sort
+
+
+options.define('port', default=8888, type=int, help="Server port")
+options.define('mongo', default='localhost', type=str, help="MongoDB host")
+options.define('backlog', default=8192, type=int, help="Server backlog")
+
+
+class SingleQueryHandler(JsonHandler):
+
+    @gen.coroutine
+    def get(self):
+        world = yield db.World.find_one(randint(1, 10000))
+        world = {self.ID: int(world['_id']),
+                 self.RANDOM_NUMBER: int(world[self.RANDOM_NUMBER])
+                 }
+
+        response = json.dumps(world)
+        self.finish(response)
+
+
+class MultipleQueriesHandler(JsonHandler):
+    @gen.coroutine
+    def get(self):
+        try:
+            queries = int(self.get_argument(self.QUERIES))
+        except Exception:
+            queries = 1
+        else:
+            if queries < 1:
+                queries = 1
+            elif queries > 500:
+                queries = 500
+
+        worlds = yield [db.World.find_one(randint(1, 10000)) for _ in xrange(queries)]
+
+        worlds = [{self.ID: int(world['_id']),
+                   self.RANDOM_NUMBER: int(world[self.RANDOM_NUMBER])}
+                  for world in worlds]
+
+        self.finish(json.dumps(worlds))
+
+
+class UpdateHandler(JsonHandler):
+    @gen.coroutine
+    def get(self):
+        try:
+            queries = int(self.get_argument(self.QUERIES))
+        except Exception:
+            queries = 1
+        else:
+            if queries < 1:
+                queries = 1
+            elif queries > 500:
+                queries = 500
+
+        worlds = []
+        updates = []
+        for _ in xrange(queries):
+            world = yield db.World.find_one(randint(1, 10000))
+            new_value = randint(1, 10000)
+
+            updates.append(db.World.update_one({'_id': world['_id']}, {"$set": {self.RANDOM_NUMBER: new_value}}))
+            worlds.append({self.ID: world['_id'],
+                   self.RANDOM_NUMBER: world[self.RANDOM_NUMBER]})
+
+        yield updates
+        self.finish(json.dumps(worlds))
+
+
+class FortuneHandler(BaseHandler):
+    @gen.coroutine
+    def get(self):
+        fortunes = []
+        cursor = db.Fortune.find()
+
+        while (yield cursor.fetch_next):
+            fortunes.append(cursor.next_object())
+        fortunes.append({self.ID: 0, 'message': 'Additional fortune added at request time.'})
+        fortunes.sort(fortunes_sort)
+        self.render('fortunes.html', fortunes=fortunes)
+
+
+application = tornado.web.Application([
+    (r"/json", JsonHelloWorldHandler),
+    (r"/plaintext", PlaintextHelloWorldHandler),
+    (r"/db", SingleQueryHandler),
+    (r"/queries", MultipleQueriesHandler),
+    (r"/updates", UpdateHandler),
+    (r"/fortunes", FortuneHandler),
+],
+    template_path="templates"
+)
+
+
+if __name__ == "__main__":
+    tornado.options.parse_command_line()
+    server = tornado.httpserver.HTTPServer(application)
+    server.bind(options.port, backlog=options.backlog)
+    server.start(0)
+
+    ioloop = tornado.ioloop.IOLoop.instance()
+    db = motor.MotorClient(options.mongo).hello_world
+    ioloop.start()

+ 113 - 0
frameworks/Python/tornado/server_py3.py

@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+
+import json
+import motor
+import tornado.ioloop
+import tornado.web
+import tornado.httpserver
+
+from random import randint
+from tornado.options import options
+from commons import JsonHandler, JsonHelloWorldHandler, PlaintextHelloWorldHandler
+from tornado.ioloop import IOLoop
+
+IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')
+
+
+options.define('port', default=8888, type=int, help="Server port")
+options.define('mongo', default='localhost', type=str, help="MongoDB host")
+options.define('backlog', default=8192, type=int, help="Server backlog")
+
+
+class SingleQueryHandler(JsonHandler):
+
+    async def get(self):
+        world = await db.World.find_one(randint(1, 10000))
+        world = {self.ID: int(world['_id']),
+                 self.RANDOM_NUMBER: int(world[self.RANDOM_NUMBER])
+                 }
+
+        response = json.dumps(world)
+        self.finish(response)
+
+
+class MultipleQueriesHandler(JsonHandler):
+    async def get(self):
+        try:
+            queries = int(self.get_argument(self.QUERIES))
+        except Exception:
+            queries = 1
+        else:
+            if queries < 1:
+                queries = 1
+            elif queries > 500:
+                queries = 500
+
+        worlds = []
+        for future in [db.World.find_one(randint(1, 10000)) for _ in range(queries)]:
+            world = await future
+
+            worlds.append({self.ID: int(world['_id']),
+                    self.RANDOM_NUMBER: int(world[self.RANDOM_NUMBER])})
+
+        self.finish(json.dumps(worlds))
+
+
+class UpdateHandler(JsonHandler):
+    async def get(self):
+        try:
+            queries = int(self.get_argument(self.QUERIES))
+        except Exception:
+            queries = 1
+        else:
+            if queries < 1:
+                queries = 1
+            elif queries > 500:
+                queries = 500
+
+        worlds = []
+        futures = [db.World.find_one(randint(1, 10000)) for _ in range(queries)]
+
+        for world in futures:
+            world = await world
+            new_value = randint(1, 10000)
+            await db.World.update_one({'_id': world['_id']}, {"$set": {self.RANDOM_NUMBER: new_value}})
+
+            worlds.append({self.ID: int(world['_id']),
+                    self.RANDOM_NUMBER: world[self.RANDOM_NUMBER]})
+        self.finish(json.dumps(worlds))
+
+
+class FortuneHandler(JsonHandler):
+    async def get(self):
+        fortunes = []
+
+        async for fortune in db.Fortune.find():
+            fortunes.append(fortune)
+        fortunes.append({self.ID: 0, 'message': 'Additional fortune added at request time.'})
+
+        fortunes.sort(key=lambda f: f['message'])
+        self.render('fortunes.html', fortunes=fortunes)
+
+
+application = tornado.web.Application([
+    (r"/json", JsonHelloWorldHandler),
+    (r"/plaintext", PlaintextHelloWorldHandler),
+    (r"/db", SingleQueryHandler),
+    (r"/queries", MultipleQueriesHandler),
+    (r"/updates", UpdateHandler),
+    (r"/fortunes", FortuneHandler),
+],
+    template_path="templates"
+)
+
+
+if __name__ == "__main__":
+    tornado.options.parse_command_line()
+    server = tornado.httpserver.HTTPServer(application)
+    server.bind(options.port, backlog=options.backlog)
+    server.start(0)
+
+    ioloop = tornado.ioloop.IOLoop.instance()
+    db = motor.MotorClient(options.mongo).hello_world
+    ioloop.start()

+ 1 - 1
frameworks/Python/tornado/setup_pg.sh

@@ -4,4 +4,4 @@ fw_depends postgresql python2
 
 
 pip install --install-option="--prefix=${PY2_ROOT}" -r $TROOT/requirements.txt
 pip install --install-option="--prefix=${PY2_ROOT}" -r $TROOT/requirements.txt
 
 
-python server.py --port=8080 --postgres=$DBHOST --logging=error &
+python server_pg.py --port=8080 --postgres=$DBHOST --logging=error &

+ 0 - 0
frameworks/Python/tornado/setup.sh → frameworks/Python/tornado/setup_py2.sh


+ 7 - 0
frameworks/Python/tornado/setup_pypy.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+fw_depends mongodb pypy
+
+pip install --install-option="--prefix=${PYPY_ROOT}" -r $TROOT/requirements.txt
+
+python server_py2.py --port=8080 --mongo=$DBHOST --logging=error &

+ 5 - 3
frameworks/Python/tornado/source_code

@@ -1,3 +1,5 @@
-./tornado/server.py
-./tornado/setup.py
-./tornado/setup_pypy.py
+./tornado/commons.py
+./tornado/server_pg.py
+./tornado/server_py2.py
+./tornado/server_py3.py
+./tornado/templates/fortunes.html

+ 13 - 0
frameworks/Python/tornado/templates/fortunes.html

@@ -0,0 +1,13 @@
+{% whitespace oneline %}
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+{% for fortune in fortunes %}
+<tr><td>{{ fortune['id'] }}</td><td>{{ fortune['message'] }}</td></tr>
+{% end %}
+</table>
+</body>
+</html>