Skip to content

Commit e5ab1a1

Browse files
Add 3 new routes for photon-http + postgres (#10214)
1 parent 291c258 commit e5ab1a1

File tree

5 files changed

+170
-13
lines changed

5 files changed

+170
-13
lines changed

frameworks/D/photon-http/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ A benchmark for photon fiber scheduler for D running with minimalistic http serv
88

99
* [JSON](./source/app.d)
1010
* [PLAINTEXT](./source/app.d)
11+
* [DB](./source/app.d)
12+
* [QUERIES](./source/app.d)
13+
* [UPDATES](./source/app.d)
1114

1215
## Important Libraries
16+
1317
The tests were run with:
1418
* [photon](https://github.com/DmitryOlshansky/photon)
1519
* [photon-http][https://github.com/DmitryOlshansky/photon-http]
20+
* [dpq2](https://github.com/denizzzka/dpq2)
1621

1722
## Test URLs
1823

@@ -23,3 +28,16 @@ http://localhost:8080/json
2328
### PLAINTEXT
2429

2530
http://localhost:8080/plaintext
31+
32+
### Data-Store/Database Mapping Test
33+
34+
http://localhost:8080/db
35+
36+
### Multiple queries
37+
38+
http://localhost:8080/queries?queries=...
39+
40+
### Multiple queries with updates
41+
42+
http://localhost:8080/updates?queries=...
43+

frameworks/D/photon-http/benchmark_config.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
"tests": [
44
{
55
"default": {
6+
"update_url": "/updates?queries=",
7+
"query_url": "/queries?queries=",
8+
"db_url": "/db",
69
"json_url": "/json",
710
"plaintext_url": "/plaintext",
811
"port": 8080,
912
"approach": "Realistic",
1013
"classification": "Platform",
11-
"database": "None",
14+
"database": "Postgres",
1215
"framework": "None",
1316
"language": "D",
1417
"flavor": "None",
15-
"orm": "None",
18+
"orm": "raw",
1619
"platform": "None",
1720
"webserver": "None",
1821
"os": "Linux",

frameworks/D/photon-http/dub.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
],
55
"copyright": "Copyright © 2025, Dmitry Olshansky",
66
"dependencies": {
7+
"dpq2": "~>1.2.4",
8+
"mir-random": "~>2.2.20",
79
"mir-ion": "~>2.3.4",
810
"xbuf" : "~>0.2.1",
9-
"photon": "~>0.18.5",
11+
"photon": "~>0.18.10",
1012
"photon-http": "~>0.6.8"
1113
},
1214
"description": "Benchmark of photon-http",

frameworks/D/photon-http/photon-http.dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ WORKDIR /app
55

66
COPY . .
77

8+
RUN apt-get update -yqq && apt-get install -yqq libpq-dev zlib1g-dev
9+
810
RUN dub build -b release --compiler=ldc2
911

1012
EXPOSE 8080

frameworks/D/photon-http/source/app.d

Lines changed: 142 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,164 @@
11
import std.stdio;
22
import std.socket;
33
import std.array;
4+
import std.algorithm;
5+
import std.conv;
6+
import std.ascii;
47

58
import mir.ser;
69
import mir.ser.json;
710

11+
import core.time;
12+
813
import std.range.primitives;
914

1015
import glow.xbuf;
1116

1217
import photon, photon.http;
1318

14-
struct Message
15-
{
19+
import mir.random : unpredictableSeedOf;
20+
import mir.random.variable : UniformVariable;
21+
import mir.random.engine.xorshift : Xorshift;
22+
23+
import dpq2;
24+
25+
struct Message {
1626
string message;
1727
}
1828

29+
struct WorldResponse {
30+
int id;
31+
int randomNumber;
32+
}
33+
34+
enum connectionInfo = "host=tfb-database port=5432 "
35+
~ "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass";
36+
enum worldSize = 10000;
37+
enum poolSize = 64;
38+
39+
shared Pool!Connection connectionPool;
40+
1941
class BenchmarkProcessor : HttpProcessor {
20-
HttpHeader[] plainText = [HttpHeader("Content-Type", "text/plain; charset=utf-8")];
21-
HttpHeader[] json = [HttpHeader("Content-Type", "application/json")];
42+
HttpHeader[] plainTextHeaders = [HttpHeader("Content-Type", "text/plain; charset=utf-8")];
43+
HttpHeader[] jsonHeaders = [HttpHeader("Content-Type", "application/json")];
2244
Buffer!char jsonBuf;
45+
Buffer!WorldResponse worlds;
46+
UniformVariable!uint uniformVariable;
47+
Xorshift gen;
48+
2349
this(Socket sock) {
2450
super(sock);
51+
gen = Xorshift(unpredictableSeed!uint);
52+
uniformVariable = UniformVariable!uint(1, worldSize);
2553
jsonBuf = Buffer!char(256);
54+
worlds = Buffer!WorldResponse(500);
2655
}
2756

2857
override void handle(HttpRequest req) {
2958
if (req.uri == "/plaintext") {
30-
respondWith("Hello, world!", HttpStatus.OK, plainText);
59+
plaintext();
3160
} else if(req.uri == "/json") {
32-
jsonBuf.clear();
33-
serializeJsonPretty!""(jsonBuf, Message("Hello, World!"));
34-
respondWith(jsonBuf.data, HttpStatus.OK, json);
35-
} else {
36-
respondWith("Not found", HttpStatus.NotFound, plainText);
61+
json();
62+
} else if(req.uri == "/db") {
63+
db();
64+
} else if(req.uri.startsWith("/queries")) {
65+
queries(req.uri);
66+
} else if(req.uri.startsWith("/updates")) {
67+
updates(req.uri);
68+
}
69+
else {
70+
respondWith("Not found", HttpStatus.NotFound, plainTextHeaders);
71+
}
72+
}
73+
74+
final void plaintext() {
75+
respondWith("Hello, world!", HttpStatus.OK, plainTextHeaders);
76+
}
77+
78+
final void json() {
79+
jsonBuf.clear();
80+
serializeJsonPretty!""(jsonBuf, Message("Hello, World!"));
81+
respondWith(jsonBuf.data, HttpStatus.OK, jsonHeaders);
82+
}
83+
84+
final void db() {
85+
jsonBuf.clear();
86+
int id = uniformVariable(gen);
87+
auto c = connectionPool.acquire();
88+
scope(exit) connectionPool.release(c);
89+
QueryParams qp;
90+
qp.preparedStatementName("db_prpq");
91+
qp.argsVariadic(id);
92+
immutable result = c.execPrepared(qp).rangify.front;
93+
auto w = WorldResponse(id, result[0].as!PGinteger);
94+
serializeJsonPretty!""(jsonBuf, w);
95+
respondWith(jsonBuf.data, HttpStatus.OK, jsonHeaders);
96+
}
97+
98+
// GET /queries?queries=...
99+
final void queries(const(char)[] uri) {
100+
jsonBuf.clear();
101+
worlds.clear();
102+
auto c = connectionPool.acquire();
103+
scope(exit) connectionPool.release(c);
104+
105+
int count = 1;
106+
auto i = uri.indexOf("?queries=");
107+
if (i > 0 && i + 9 <= uri.length && isDigit(uri[i+9]))
108+
{
109+
try count = min(max(uri[i+9..$].to!int, 1), 500);
110+
catch (ConvException) {}
111+
}
112+
113+
QueryParams qp;
114+
qp.preparedStatementName("db_prpq");
115+
foreach (_; 0..count) {
116+
int id = uniformVariable(gen);
117+
qp.argsVariadic(id);
118+
immutable result = c.execPrepared(qp).rangify.front;
119+
worlds.put(WorldResponse(id, result[0].as!PGinteger));
120+
}
121+
serializeJsonPretty!""(jsonBuf, worlds.data);
122+
respondWith(jsonBuf.data, HttpStatus.OK, jsonHeaders);
123+
}
124+
125+
// GET /updates?queries=...
126+
final void updates(const(char)[] uri) {
127+
jsonBuf.clear();
128+
worlds.clear();
129+
auto c = connectionPool.acquire();
130+
scope(exit) connectionPool.release(c);
131+
132+
int count = 1;
133+
auto i = uri.indexOf("?queries=");
134+
if (i > 0 && i + 9 <= uri.length && isDigit(uri[i+9]))
135+
{
136+
try count = min(max(uri[i+9..$].to!int, 1), 500);
137+
catch (ConvException) {}
138+
}
139+
140+
QueryParams qp;
141+
qp.preparedStatementName("db_prpq");
142+
143+
QueryParams qp_update;
144+
qp_update.preparedStatementName("db_update_prpq");
145+
146+
foreach (_; 0..count) {
147+
int id = uniformVariable(gen);
148+
qp.argsVariadic(id);
149+
immutable result = c.execPrepared(qp).rangify.front;
150+
auto w = WorldResponse(id, result[0].as!PGinteger);
151+
152+
// update random number
153+
w.randomNumber = uniformVariable(gen);
154+
qp_update.argsVariadic(w.randomNumber, id);
155+
156+
// persist to DB
157+
c.execPrepared(qp_update);
158+
worlds.put(w);
37159
}
160+
serializeJsonPretty!""(jsonBuf, worlds.data);
161+
respondWith(jsonBuf.data, HttpStatus.OK, jsonHeaders);
38162
}
39163
}
40164

@@ -75,6 +199,14 @@ void server() {
75199

76200
void main() {
77201
initPhoton();
202+
connectionPool = pool(poolSize, 15.seconds, () {
203+
auto c = new Connection(connectionInfo);
204+
c.prepareEx("db_prpq", "SELECT randomNumber, id FROM world WHERE id = $1");
205+
c.prepareEx("db_update_prpq", "UPDATE world SET randomNumber = $1 WHERE id = $2");
206+
return c;
207+
}, (ref Connection c) {
208+
destroy(c);
209+
});
78210
go(() => server());
79211
runScheduler();
80212
}

0 commit comments

Comments
 (0)