|
@@ -1,5 +1,4 @@
|
|
import multiprocessing
|
|
import multiprocessing
|
|
-from pathlib import Path
|
|
|
|
from random import randint, sample
|
|
from random import randint, sample
|
|
|
|
|
|
import asyncpg
|
|
import asyncpg
|
|
@@ -10,19 +9,22 @@ from panther.events import Event
|
|
from panther.request import Request
|
|
from panther.request import Request
|
|
from panther.response import Response, PlainTextResponse, HTMLResponse
|
|
from panther.response import Response, PlainTextResponse, HTMLResponse
|
|
|
|
|
|
-READ_ROW_SQL = 'SELECT "id", "randomnumber" FROM "world" WHERE id = $1'
|
|
|
|
-WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2'
|
|
|
|
-ADDITIONAL_ROW = [0, 'Additional fortune added at request time.']
|
|
|
|
-MAX_POOL_SIZE = 1000 // multiprocessing.cpu_count()
|
|
|
|
-MIN_POOL_SIZE = max(int(MAX_POOL_SIZE / 2), 1)
|
|
|
|
|
|
+cpu_count = multiprocessing.cpu_count()
|
|
|
|
+MAX_POOL_SIZE = 1000 // cpu_count
|
|
|
|
+MIN_POOL_SIZE = max(MAX_POOL_SIZE // 2, 1)
|
|
|
|
|
|
-pool = None
|
|
|
|
|
|
+connection_pool = None
|
|
|
|
+
|
|
|
|
+fortune_template = jinja2.Environment(
|
|
|
|
+ loader=jinja2.FileSystemLoader('templates'),
|
|
|
|
+ autoescape=True
|
|
|
|
+).get_template('fortune.html')
|
|
|
|
|
|
|
|
|
|
@Event.startup
|
|
@Event.startup
|
|
-async def create_db_pool():
|
|
|
|
- global pool
|
|
|
|
- pool = await asyncpg.create_pool(
|
|
|
|
|
|
+async def on_startup():
|
|
|
|
+ global connection_pool
|
|
|
|
+ connection_pool = await asyncpg.create_pool(
|
|
user='benchmarkdbuser',
|
|
user='benchmarkdbuser',
|
|
password='benchmarkdbpass',
|
|
password='benchmarkdbpass',
|
|
database='hello_world',
|
|
database='hello_world',
|
|
@@ -34,60 +36,42 @@ async def create_db_pool():
|
|
|
|
|
|
|
|
|
|
@Event.shutdown
|
|
@Event.shutdown
|
|
-async def clean_db_pool():
|
|
|
|
- await pool.close()
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-with Path('templates/fortune.html').open() as f:
|
|
|
|
- fortune_template = jinja2.Template(f.read())
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def get_num_queries(request):
|
|
|
|
- value = request.query_params.get('queries')
|
|
|
|
- if value is None:
|
|
|
|
- return 1
|
|
|
|
-
|
|
|
|
- try:
|
|
|
|
- query_count = int(value)
|
|
|
|
- except ValueError:
|
|
|
|
- return 1
|
|
|
|
- if query_count < 1:
|
|
|
|
- return 1
|
|
|
|
- if query_count > 500:
|
|
|
|
- return 500
|
|
|
|
- return query_count
|
|
|
|
|
|
+async def on_shutdown():
|
|
|
|
+ await connection_pool.close()
|
|
|
|
|
|
|
|
|
|
@API()
|
|
@API()
|
|
-async def json_serialization():
|
|
|
|
|
|
+def json_serialization():
|
|
return Response(data={'message': 'Hello, world!'})
|
|
return Response(data={'message': 'Hello, world!'})
|
|
|
|
|
|
|
|
|
|
@API()
|
|
@API()
|
|
async def single_database_query():
|
|
async def single_database_query():
|
|
row_id = randint(1, 10000)
|
|
row_id = randint(1, 10000)
|
|
- async with pool.acquire() as connection:
|
|
|
|
- number = await connection.fetchval(READ_ROW_SQL, row_id)
|
|
|
|
|
|
+ async with connection_pool.acquire() as connection:
|
|
|
|
+ number = await connection.fetchval('SELECT id, randomnumber FROM world WHERE id = $1', row_id)
|
|
return Response(data={'id': row_id, 'randomNumber': number})
|
|
return Response(data={'id': row_id, 'randomNumber': number})
|
|
|
|
|
|
|
|
|
|
@API()
|
|
@API()
|
|
async def multiple_database_queries(request: Request):
|
|
async def multiple_database_queries(request: Request):
|
|
- num_queries = get_num_queries(request)
|
|
|
|
- row_ids = sample(range(1, 10000), num_queries)
|
|
|
|
-
|
|
|
|
- async with pool.acquire() as connection:
|
|
|
|
- statement = await connection.prepare(READ_ROW_SQL)
|
|
|
|
|
|
+ try:
|
|
|
|
+ count = int(request.query_params.get('queries', 1))
|
|
|
|
+ except (ValueError, TypeError):
|
|
|
|
+ count = 1
|
|
|
|
+ row_ids = sample(range(1, 10000), min(max(count, 1), 500))
|
|
|
|
+ async with connection_pool.acquire() as connection:
|
|
|
|
+ statement = await connection.prepare('SELECT id, randomnumber FROM world WHERE id = $1')
|
|
worlds = [{'id': i, 'randomNumber': await statement.fetchval(i)} for i in row_ids]
|
|
worlds = [{'id': i, 'randomNumber': await statement.fetchval(i)} for i in row_ids]
|
|
-
|
|
|
|
return Response(data=worlds)
|
|
return Response(data=worlds)
|
|
|
|
|
|
|
|
|
|
@API()
|
|
@API()
|
|
async def fortunes():
|
|
async def fortunes():
|
|
- async with pool.acquire() as connection:
|
|
|
|
|
|
+ async with connection_pool.acquire() as connection:
|
|
fortune_records = await connection.fetch('SELECT * FROM Fortune')
|
|
fortune_records = await connection.fetch('SELECT * FROM Fortune')
|
|
- fortune_records.append(ADDITIONAL_ROW)
|
|
|
|
|
|
+ fortune_records = [(row['id'], row['message']) for row in fortune_records]
|
|
|
|
+ fortune_records.append((0, 'Additional fortune added at request time.'))
|
|
fortune_records.sort(key=lambda row: row[1])
|
|
fortune_records.sort(key=lambda row: row[1])
|
|
data = fortune_template.render(fortunes=fortune_records)
|
|
data = fortune_template.render(fortunes=fortune_records)
|
|
return HTMLResponse(data=data)
|
|
return HTMLResponse(data=data)
|
|
@@ -95,24 +79,27 @@ async def fortunes():
|
|
|
|
|
|
@API()
|
|
@API()
|
|
async def database_updates(request: Request):
|
|
async def database_updates(request: Request):
|
|
- num_queries = get_num_queries(request)
|
|
|
|
|
|
+ try:
|
|
|
|
+ count = int(request.query_params.get('queries', 1))
|
|
|
|
+ except (ValueError, TypeError):
|
|
|
|
+ count = 1
|
|
|
|
+ num_queries = min(max(count, 1), 500)
|
|
|
|
+
|
|
updates = list(zip(
|
|
updates = list(zip(
|
|
sample(range(1, 10000), num_queries),
|
|
sample(range(1, 10000), num_queries),
|
|
sorted(sample(range(1, 10000), num_queries))
|
|
sorted(sample(range(1, 10000), num_queries))
|
|
))
|
|
))
|
|
-
|
|
|
|
worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates]
|
|
worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates]
|
|
-
|
|
|
|
- async with pool.acquire() as connection:
|
|
|
|
- statement = await connection.prepare(READ_ROW_SQL)
|
|
|
|
|
|
+ async with connection_pool.acquire() as connection:
|
|
|
|
+ statement = await connection.prepare('SELECT id, randomnumber FROM world WHERE id = $1')
|
|
for _, row_id in updates:
|
|
for _, row_id in updates:
|
|
await statement.fetchval(row_id)
|
|
await statement.fetchval(row_id)
|
|
- await connection.executemany(WRITE_ROW_SQL, updates)
|
|
|
|
|
|
+ await connection.executemany('UPDATE world SET randomnumber = $1 WHERE id = $2', updates)
|
|
return Response(data=worlds)
|
|
return Response(data=worlds)
|
|
|
|
|
|
|
|
|
|
@API()
|
|
@API()
|
|
-async def plaintext():
|
|
|
|
|
|
+def plaintext():
|
|
return PlainTextResponse(b'Hello, world!')
|
|
return PlainTextResponse(b'Hello, world!')
|
|
|
|
|
|
|
|
|