|
@@ -1,192 +1,116 @@
|
|
#!/usr/bin/env python
|
|
#!/usr/bin/env python
|
|
-from functools import partial
|
|
|
|
-import json
|
|
|
|
|
|
+from collections import namedtuple
|
|
from operator import attrgetter
|
|
from operator import attrgetter
|
|
-import os
|
|
|
|
from random import randint
|
|
from random import randint
|
|
import sys
|
|
import sys
|
|
-from email.utils import formatdate
|
|
|
|
|
|
|
|
-import flask
|
|
|
|
from flask import Flask, request, render_template, make_response, jsonify
|
|
from flask import Flask, request, render_template, make_response, jsonify
|
|
-from flask_sqlalchemy import SQLAlchemy
|
|
|
|
-from sqlalchemy import create_engine
|
|
|
|
-from sqlalchemy.ext import baked
|
|
|
|
|
|
+from pony import orm
|
|
|
|
|
|
if sys.version_info[0] == 3:
|
|
if sys.version_info[0] == 3:
|
|
xrange = range
|
|
xrange = range
|
|
-
|
|
|
|
_is_pypy = hasattr(sys, 'pypy_version_info')
|
|
_is_pypy = hasattr(sys, 'pypy_version_info')
|
|
|
|
+if _is_pypy:
|
|
|
|
+ from psycopg2cffi import compat
|
|
|
|
+ compat.register()
|
|
|
|
|
|
-DBDRIVER = 'mysql+pymysql' if _is_pypy else 'mysql' # mysqlclient is slow on PyPy
|
|
|
|
|
|
+DBDRIVER = 'postgres'
|
|
DBHOST = 'tfb-database'
|
|
DBHOST = 'tfb-database'
|
|
|
|
|
|
-
|
|
|
|
# setup
|
|
# setup
|
|
|
|
|
|
app = Flask(__name__)
|
|
app = Flask(__name__)
|
|
-app.config['SQLALCHEMY_DATABASE_URI'] = DBDRIVER + '://benchmarkdbuser:benchmarkdbpass@%s:3306/hello_world?charset=utf8' % DBHOST
|
|
|
|
-app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
|
|
|
|
+app.config['STORM_DATABASE_URI'] = "{DBDRIVER}://benchmarkdbuser:benchmarkdbpass@{DBHOST}:5432/hello_world".format(DBDRIVER=DBDRIVER, DBHOST=DBHOST)
|
|
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
|
|
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
|
|
-db = SQLAlchemy(app)
|
|
|
|
-dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'], connect_args={'autocommit': True}, pool_reset_on_return=None)
|
|
|
|
-
|
|
|
|
-bakery = baked.bakery()
|
|
|
|
-
|
|
|
|
|
|
+db = orm.Database()
|
|
|
|
+db.bind(DBDRIVER, host=DBHOST, port=5432, user="benchmarkdbuser", password="benchmarkdbpass", database="hello_world")
|
|
|
|
|
|
-# models
|
|
|
|
|
|
|
|
-class World(db.Model):
|
|
|
|
- __tablename__ = "world"
|
|
|
|
- id = db.Column(db.Integer, primary_key=True)
|
|
|
|
- randomNumber = db.Column(db.Integer)
|
|
|
|
|
|
+class World(db.Entity):
|
|
|
|
+ _table_ = "world"
|
|
|
|
+ id = orm.PrimaryKey(int)
|
|
|
|
+ randomNumber = orm.Required(int, column="randomnumber")
|
|
|
|
|
|
- # http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask
|
|
|
|
- @property
|
|
|
|
- def serialize(self):
|
|
|
|
|
|
+ def to_dict(self):
|
|
"""Return object data in easily serializeable format"""
|
|
"""Return object data in easily serializeable format"""
|
|
return {
|
|
return {
|
|
'id' : self.id,
|
|
'id' : self.id,
|
|
'randomNumber': self.randomNumber
|
|
'randomNumber': self.randomNumber
|
|
}
|
|
}
|
|
|
|
|
|
- @staticmethod
|
|
|
|
- def get(ident):
|
|
|
|
- baked_query = bakery(lambda s: s.query(World))
|
|
|
|
- return baked_query(db.session()).get(ident)
|
|
|
|
|
|
|
|
|
|
+class Fortune(db.Entity):
|
|
|
|
+ _table_ = "fortune"
|
|
|
|
+ id = orm.PrimaryKey(int, auto=True)
|
|
|
|
+ message = orm.Required(str)
|
|
|
|
|
|
-class Fortune(db.Model):
|
|
|
|
- __tablename__ = "fortune"
|
|
|
|
- id = db.Column(db.Integer, primary_key=True)
|
|
|
|
- message = db.Column(db.String)
|
|
|
|
|
|
|
|
|
|
+db.generate_mapping(create_tables=False)
|
|
|
|
|
|
-# views
|
|
|
|
|
|
|
|
-# flask.jsonify doesn't allow array at top level for security concern.
|
|
|
|
-# So we should have oriiginal one.
|
|
|
|
-def json_response(obj):
|
|
|
|
- res = make_response(json.dumps(obj))
|
|
|
|
- res.mimetype = "application/json"
|
|
|
|
- return add_date_header(res)
|
|
|
|
|
|
+def get_num_queries():
|
|
|
|
+ try:
|
|
|
|
+ num_queries = request.args.get("queries", 1, type=int)
|
|
|
|
+ except ValueError:
|
|
|
|
+ num_queries = 1
|
|
|
|
+ if num_queries < 1:
|
|
|
|
+ return 1
|
|
|
|
+ if num_queries > 500:
|
|
|
|
+ return 500
|
|
|
|
+ return num_queries
|
|
|
|
|
|
|
|
|
|
-def add_date_header(res):
|
|
|
|
- res.headers['Date'] = formatdate(timeval=None, localtime=False, usegmt=True)
|
|
|
|
- return res
|
|
|
|
|
|
+def generate_ids(num_queries):
|
|
|
|
+ ids = {randint(1, 10000) for _ in xrange(num_queries)}
|
|
|
|
+ while len(ids) < num_queries:
|
|
|
|
+ ids.add(randint(1, 10000))
|
|
|
|
+ return list(sorted(ids))
|
|
|
|
|
|
|
|
|
|
@app.route("/json")
|
|
@app.route("/json")
|
|
def hello():
|
|
def hello():
|
|
- return add_date_header(jsonify(message='Hello, World!'))
|
|
|
|
|
|
+ return jsonify(message='Hello, World!')
|
|
|
|
|
|
|
|
|
|
[email protected]("/db")
|
|
|
|
|
|
[email protected]("/query")
|
|
def get_random_world():
|
|
def get_random_world():
|
|
- num_queries = request.args.get("queries", 1, type=int)
|
|
|
|
- if num_queries < 1:
|
|
|
|
- num_queries = 1
|
|
|
|
- if num_queries > 500:
|
|
|
|
- num_queries = 500
|
|
|
|
- worlds = [World.get(randint(1, 10000)).serialize
|
|
|
|
- for _ in xrange(num_queries)]
|
|
|
|
- return json_response(worlds)
|
|
|
|
|
|
+ with orm.db_session(serializable=False):
|
|
|
|
+ worlds = [World[ident].to_dict()
|
|
|
|
+ for ident in generate_ids(get_num_queries())]
|
|
|
|
+ return jsonify(worlds)
|
|
|
|
|
|
|
|
|
|
[email protected]("/dbs")
|
|
|
|
|
|
[email protected]("/db")
|
|
def get_random_world_single():
|
|
def get_random_world_single():
|
|
wid = randint(1, 10000)
|
|
wid = randint(1, 10000)
|
|
- worlds = World.get(wid).serialize
|
|
|
|
- return json_response(worlds)
|
|
|
|
-
|
|
|
|
|
|
+ with orm.db_session(serializable=False):
|
|
|
|
+ world = World[wid]
|
|
|
|
+ return jsonify(world.to_dict())
|
|
|
|
|
|
[email protected]("/dbraw")
|
|
|
|
-def get_random_world_raw():
|
|
|
|
- connection = dbraw_engine.connect()
|
|
|
|
- num_queries = request.args.get("queries", 1, type=int)
|
|
|
|
- if num_queries < 1:
|
|
|
|
- num_queries = 1
|
|
|
|
- if num_queries > 500:
|
|
|
|
- num_queries = 500
|
|
|
|
- worlds = []
|
|
|
|
- for i in xrange(num_queries):
|
|
|
|
- wid = randint(1, 10000)
|
|
|
|
- result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
|
|
|
|
- worlds.append({'id': result[0], 'randomNumber': result[1]})
|
|
|
|
- connection.close()
|
|
|
|
- return json_response(worlds)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
[email protected]("/dbsraw")
|
|
|
|
-def get_random_world_single_raw():
|
|
|
|
- connection = dbraw_engine.connect()
|
|
|
|
- wid = randint(1, 10000)
|
|
|
|
- result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
|
|
|
|
- worlds = {'id': result[0], 'randomNumber': result[1]}
|
|
|
|
- connection.close()
|
|
|
|
- return json_response(worlds)
|
|
|
|
|
|
|
|
@app.route("/fortunes")
|
|
@app.route("/fortunes")
|
|
def get_fortunes():
|
|
def get_fortunes():
|
|
- fortunes = list(Fortune.query.all())
|
|
|
|
- fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
|
|
|
|
|
|
+ with orm.db_session(serializable=False):
|
|
|
|
+ fortunes = list(orm.select(fortune for fortune in Fortune))
|
|
|
|
+ tmp_fortune = namedtuple("Fortune", ["id", "message"])
|
|
|
|
+ fortunes.append(tmp_fortune(id=0, message="Additional fortune added at request time."))
|
|
fortunes.sort(key=attrgetter('message'))
|
|
fortunes.sort(key=attrgetter('message'))
|
|
- return add_date_header(make_response(render_template('fortunes.html', fortunes=fortunes)))
|
|
|
|
-
|
|
|
|
[email protected]("/fortunesraw")
|
|
|
|
-def get_fortunes_raw():
|
|
|
|
- res = dbraw_engine.execute("SELECT * FROM fortune")
|
|
|
|
- fortunes = res.fetchall()
|
|
|
|
- res.close()
|
|
|
|
- fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
|
|
|
|
- fortunes.sort(key=attrgetter('message'))
|
|
|
|
- return add_date_header(make_response(render_template('fortunes.html', fortunes=fortunes)))
|
|
|
|
|
|
+ return render_template('fortunes.html', fortunes=fortunes)
|
|
|
|
|
|
|
|
|
|
@app.route("/updates")
|
|
@app.route("/updates")
|
|
def updates():
|
|
def updates():
|
|
"""Test 5: Database Updates"""
|
|
"""Test 5: Database Updates"""
|
|
- num_queries = request.args.get('queries', 1, type=int)
|
|
|
|
- if num_queries < 1:
|
|
|
|
- num_queries = 1
|
|
|
|
- if num_queries > 500:
|
|
|
|
- num_queries = 500
|
|
|
|
-
|
|
|
|
|
|
+ num_queries = get_num_queries()
|
|
|
|
+ ids = generate_ids(num_queries)
|
|
|
|
+ ids.sort()
|
|
worlds = []
|
|
worlds = []
|
|
- rp = partial(randint, 1, 10000)
|
|
|
|
- ids = [rp() for _ in xrange(num_queries)]
|
|
|
|
- ids.sort() # To avoid deadlock
|
|
|
|
- for id in ids:
|
|
|
|
- world = World.get(id)
|
|
|
|
- world.randomNumber = rp()
|
|
|
|
- worlds.append(world.serialize)
|
|
|
|
- res = json_response(worlds)
|
|
|
|
- db.session.commit()
|
|
|
|
- return res
|
|
|
|
-
|
|
|
|
-
|
|
|
|
[email protected]("/raw-updates")
|
|
|
|
-def raw_updates():
|
|
|
|
- """Test 5: Database Updates"""
|
|
|
|
- connection = dbraw_engine.connect()
|
|
|
|
- try:
|
|
|
|
- num_queries = request.args.get('queries', 1, type=int)
|
|
|
|
- if num_queries < 1:
|
|
|
|
- num_queries = 1
|
|
|
|
- if num_queries > 500:
|
|
|
|
- num_queries = 500
|
|
|
|
-
|
|
|
|
- worlds = []
|
|
|
|
- rp = partial(randint, 1, 10000)
|
|
|
|
- for i in xrange(num_queries):
|
|
|
|
- world = connection.execute("SELECT * FROM world WHERE id=%s", (rp(),)).fetchone()
|
|
|
|
- randomNumber = rp()
|
|
|
|
- worlds.append({'id': world['id'], 'randomNumber': randomNumber})
|
|
|
|
- connection.execute("UPDATE World SET randomNumber=%s WHERE id=%s", (randomNumber, world['id']))
|
|
|
|
- return json_response(worlds)
|
|
|
|
- finally:
|
|
|
|
- connection.close()
|
|
|
|
|
|
+ with orm.db_session(serializable=False):
|
|
|
|
+ for ident in ids:
|
|
|
|
+ world = World[ident]
|
|
|
|
+ world.randomNumber = randint(1, 10000)
|
|
|
|
+ worlds.append({"id": world.id, "randomNumber": world.randomNumber})
|
|
|
|
+ return jsonify(worlds)
|
|
|
|
|
|
|
|
|
|
@app.route('/plaintext')
|
|
@app.route('/plaintext')
|
|
@@ -194,7 +118,7 @@ def plaintext():
|
|
"""Test 6: Plaintext"""
|
|
"""Test 6: Plaintext"""
|
|
response = make_response(b'Hello, World!')
|
|
response = make_response(b'Hello, World!')
|
|
response.content_type = 'text/plain'
|
|
response.content_type = 'text/plain'
|
|
- return add_date_header(response)
|
|
|
|
|
|
+ return response
|
|
|
|
|
|
|
|
|
|
try:
|
|
try:
|