Skip to content

Commit 6a0d0c4

Browse files
authored
Merge pull request #96 from MDA2AV/reso006
update results - fix json
2 parents 957a34e + 7ff6349 commit 6a0d0c4

77 files changed

Lines changed: 37054 additions & 40017 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

frameworks/django/views.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,6 @@
2929
except Exception:
3030
pass
3131

32-
# Pre-compute JSON response for /json endpoint
33-
json_response_buf = None
34-
if dataset_items:
35-
items = []
36-
for d in dataset_items:
37-
item = dict(d)
38-
item['total'] = round(d['price'] * d['quantity'] * 100) / 100
39-
items.append(item)
40-
json_response_buf = json.dumps({'items': items, 'count': len(items)}).encode()
41-
4232
# SQLite
4333
db_available = os.path.exists('/data/benchmark.db')
4434
DB_QUERY = 'SELECT id, name, category, price, quantity, active, tags, rating_score, rating_count FROM items WHERE price BETWEEN ? AND ? LIMIT 50'
@@ -101,11 +91,17 @@ def baseline2(request):
10191

10292
@require_GET
10393
def json_endpoint(request):
104-
if json_response_buf:
105-
resp = HttpResponse(json_response_buf, content_type='application/json')
106-
resp['Server'] = 'django'
107-
return resp
108-
return HttpResponse('No dataset', status=500)
94+
if dataset_items is None:
95+
return HttpResponse('No dataset', status=500)
96+
items = []
97+
for d in dataset_items:
98+
item = dict(d)
99+
item['total'] = round(d['price'] * d['quantity'] * 100) / 100
100+
items.append(item)
101+
body = json.dumps({'items': items, 'count': len(items)}).encode()
102+
resp = HttpResponse(body, content_type='application/json')
103+
resp['Server'] = 'django'
104+
return resp
109105

110106

111107
@require_GET

frameworks/gleam-mist/src/httparena_gleam_mist.gleam

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import sqlight
2525
pub type Context {
2626
Context(
2727
dataset: List(DatasetItem),
28-
json_cache: BitArray,
2928
json_large_cache: BitArray,
3029
static_files: List(#(String, StaticFile)),
3130
db_available: Bool,
@@ -340,7 +339,7 @@ fn handle_json(
340339
Get ->
341340
case ctx.dataset {
342341
[] -> server_error()
343-
_ -> json_response(ctx.json_cache)
342+
_ -> json_response(build_json_response(ctx.dataset))
344343
}
345344
_ -> not_found()
346345
}
@@ -548,7 +547,6 @@ pub fn main() {
548547
Error(_) -> "/data/dataset.json"
549548
}
550549
let dataset = load_dataset(dataset_path)
551-
let json_cache = build_json_response(dataset)
552550

553551
let large_dataset = load_dataset("/data/dataset-large.json")
554552
let json_large_cache = build_json_response(large_dataset)
@@ -563,7 +561,6 @@ pub fn main() {
563561
let ctx =
564562
Context(
565563
dataset:,
566-
json_cache:,
567564
json_large_cache:,
568565
static_files:,
569566
db_available:,

frameworks/h2o/src/main.c

Lines changed: 111 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ static h2o_globalconf_t globalconf;
2020
static SSL_CTX *ssl_ctx;
2121
static __thread sqlite3 *tl_db = NULL;
2222
static __thread sqlite3_stmt *tl_db_stmt = NULL;
23-
static char *json_response;
24-
static size_t json_response_len;
23+
static yajl_val dataset_tree = NULL;
24+
static size_t dataset_count = 0;
2525
static char *json_large_response;
2626
static size_t json_large_response_len;
2727
/* Pre-loaded static files */
@@ -123,23 +123,121 @@ static int on_baseline2(h2o_handler_t *h, h2o_req_t *req)
123123
return 0;
124124
}
125125

126-
/* GET /json — return pre-serialized JSON dataset */
126+
/* GET /json — serialize JSON dataset per-request from parsed tree */
127127
static int on_json(h2o_handler_t *h, h2o_req_t *req)
128128
{
129129
(void)h;
130-
if (!json_response) {
130+
if (!dataset_tree) {
131131
h2o_send_error_500(req, "Error", "No dataset", 0);
132132
return 0;
133133
}
134-
h2o_generator_t gen;
135-
memset(&gen, 0, sizeof(gen));
136-
h2o_iovec_t body = h2o_iovec_init(json_response, json_response_len);
134+
135+
yajl_gen gen = yajl_gen_alloc(NULL);
136+
yajl_gen_map_open(gen);
137+
yajl_gen_string(gen, (const unsigned char *)"items", 5);
138+
yajl_gen_array_open(gen);
139+
140+
for (size_t i = 0; i < dataset_count; i++) {
141+
yajl_val item = YAJL_GET_ARRAY(dataset_tree)->values[i];
142+
if (!YAJL_IS_OBJECT(item)) continue;
143+
144+
const char *p_id[] = {"id", NULL};
145+
const char *p_name[] = {"name", NULL};
146+
const char *p_cat[] = {"category", NULL};
147+
const char *p_price[] = {"price", NULL};
148+
const char *p_qty[] = {"quantity", NULL};
149+
const char *p_active[] = {"active", NULL};
150+
const char *p_tags[] = {"tags", NULL};
151+
const char *p_rating[] = {"rating", NULL};
152+
153+
yajl_val vid = yajl_tree_get(item, p_id, yajl_t_number);
154+
yajl_val vname = yajl_tree_get(item, p_name, yajl_t_string);
155+
yajl_val vcat = yajl_tree_get(item, p_cat, yajl_t_string);
156+
yajl_val vprice = yajl_tree_get(item, p_price, yajl_t_number);
157+
yajl_val vqty = yajl_tree_get(item, p_qty, yajl_t_number);
158+
yajl_val vactive = yajl_tree_get(item, p_active, yajl_t_any);
159+
yajl_val vtags = yajl_tree_get(item, p_tags, yajl_t_array);
160+
yajl_val vrating = yajl_tree_get(item, p_rating, yajl_t_object);
161+
162+
double price = vprice ? YAJL_GET_DOUBLE(vprice) : 0;
163+
long long qty = vqty ? YAJL_GET_INTEGER(vqty) : 0;
164+
double total = round(price * (double)qty * 100.0) / 100.0;
165+
166+
yajl_gen_map_open(gen);
167+
168+
yajl_gen_string(gen, (const unsigned char *)"id", 2);
169+
yajl_gen_integer(gen, vid ? YAJL_GET_INTEGER(vid) : 0);
170+
171+
yajl_gen_string(gen, (const unsigned char *)"name", 4);
172+
const char *name = vname ? YAJL_GET_STRING(vname) : "";
173+
yajl_gen_string(gen, (const unsigned char *)name, strlen(name));
174+
175+
yajl_gen_string(gen, (const unsigned char *)"category", 8);
176+
const char *cat = vcat ? YAJL_GET_STRING(vcat) : "";
177+
yajl_gen_string(gen, (const unsigned char *)cat, strlen(cat));
178+
179+
yajl_gen_string(gen, (const unsigned char *)"price", 5);
180+
yajl_gen_double(gen, price);
181+
182+
yajl_gen_string(gen, (const unsigned char *)"quantity", 8);
183+
yajl_gen_integer(gen, qty);
184+
185+
yajl_gen_string(gen, (const unsigned char *)"active", 6);
186+
yajl_gen_bool(gen, vactive ? YAJL_IS_TRUE(vactive) : 0);
187+
188+
yajl_gen_string(gen, (const unsigned char *)"tags", 4);
189+
yajl_gen_array_open(gen);
190+
if (vtags) {
191+
for (size_t j = 0; j < YAJL_GET_ARRAY(vtags)->len; j++) {
192+
yajl_val t = YAJL_GET_ARRAY(vtags)->values[j];
193+
if (YAJL_IS_STRING(t)) {
194+
const char *s = YAJL_GET_STRING(t);
195+
yajl_gen_string(gen, (const unsigned char *)s, strlen(s));
196+
}
197+
}
198+
}
199+
yajl_gen_array_close(gen);
200+
201+
yajl_gen_string(gen, (const unsigned char *)"rating", 6);
202+
yajl_gen_map_open(gen);
203+
if (vrating) {
204+
const char *ps[] = {"score", NULL};
205+
const char *pc[] = {"count", NULL};
206+
yajl_val vs = yajl_tree_get(vrating, ps, yajl_t_number);
207+
yajl_val vc = yajl_tree_get(vrating, pc, yajl_t_number);
208+
yajl_gen_string(gen, (const unsigned char *)"score", 5);
209+
yajl_gen_double(gen, vs ? YAJL_GET_DOUBLE(vs) : 0);
210+
yajl_gen_string(gen, (const unsigned char *)"count", 5);
211+
yajl_gen_integer(gen, vc ? YAJL_GET_INTEGER(vc) : 0);
212+
}
213+
yajl_gen_map_close(gen);
214+
215+
yajl_gen_string(gen, (const unsigned char *)"total", 5);
216+
yajl_gen_double(gen, total);
217+
218+
yajl_gen_map_close(gen);
219+
}
220+
221+
yajl_gen_array_close(gen);
222+
yajl_gen_string(gen, (const unsigned char *)"count", 5);
223+
yajl_gen_integer(gen, (long long)dataset_count);
224+
yajl_gen_map_close(gen);
225+
226+
const unsigned char *buf;
227+
size_t len;
228+
yajl_gen_get_buf(gen, &buf, &len);
229+
230+
h2o_iovec_t body = h2o_strdup(&req->pool, (const char *)buf, len);
231+
yajl_gen_free(gen);
232+
233+
h2o_generator_t hgen;
234+
memset(&hgen, 0, sizeof(hgen));
137235
req->res.status = 200;
138236
req->res.reason = "OK";
139-
req->res.content_length = json_response_len;
237+
req->res.content_length = body.len;
140238
h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE,
141239
NULL, H2O_STRLIT("application/json"));
142-
h2o_start_response(req, &gen);
240+
h2o_start_response(req, &hgen);
143241
h2o_send(req, &body, 1, H2O_SEND_STATE_FINAL);
144242
return 0;
145243
}
@@ -452,7 +550,7 @@ static void setup_host(h2o_hostconf_t *host)
452550
h2o_compress_register(pc_compress, &compress_args);
453551
}
454552

455-
/* Load dataset.json and pre-serialize the /json response with yajl */
553+
/* Load dataset.json — parse into tree, keep in memory for per-request serialization */
456554
static void load_dataset(void)
457555
{
458556
const char *path = getenv("DATASET_PATH");
@@ -476,107 +574,9 @@ static void load_dataset(void)
476574
return;
477575
}
478576

479-
yajl_gen gen = yajl_gen_alloc(NULL);
480-
yajl_gen_map_open(gen);
481-
yajl_gen_string(gen, (const unsigned char *)"items", 5);
482-
yajl_gen_array_open(gen);
483-
484-
size_t count = YAJL_GET_ARRAY(tree)->len;
485-
for (size_t i = 0; i < count; i++) {
486-
yajl_val item = YAJL_GET_ARRAY(tree)->values[i];
487-
if (!YAJL_IS_OBJECT(item)) continue;
488-
489-
const char *p_id[] = {"id", NULL};
490-
const char *p_name[] = {"name", NULL};
491-
const char *p_cat[] = {"category", NULL};
492-
const char *p_price[] = {"price", NULL};
493-
const char *p_qty[] = {"quantity", NULL};
494-
const char *p_active[] = {"active", NULL};
495-
const char *p_tags[] = {"tags", NULL};
496-
const char *p_rating[] = {"rating", NULL};
497-
498-
yajl_val vid = yajl_tree_get(item, p_id, yajl_t_number);
499-
yajl_val vname = yajl_tree_get(item, p_name, yajl_t_string);
500-
yajl_val vcat = yajl_tree_get(item, p_cat, yajl_t_string);
501-
yajl_val vprice = yajl_tree_get(item, p_price, yajl_t_number);
502-
yajl_val vqty = yajl_tree_get(item, p_qty, yajl_t_number);
503-
yajl_val vactive = yajl_tree_get(item, p_active, yajl_t_any);
504-
yajl_val vtags = yajl_tree_get(item, p_tags, yajl_t_array);
505-
yajl_val vrating = yajl_tree_get(item, p_rating, yajl_t_object);
506-
507-
double price = vprice ? YAJL_GET_DOUBLE(vprice) : 0;
508-
long long qty = vqty ? YAJL_GET_INTEGER(vqty) : 0;
509-
double total = round(price * (double)qty * 100.0) / 100.0;
510-
511-
yajl_gen_map_open(gen);
512-
513-
yajl_gen_string(gen, (const unsigned char *)"id", 2);
514-
yajl_gen_integer(gen, vid ? YAJL_GET_INTEGER(vid) : 0);
515-
516-
yajl_gen_string(gen, (const unsigned char *)"name", 4);
517-
const char *name = vname ? YAJL_GET_STRING(vname) : "";
518-
yajl_gen_string(gen, (const unsigned char *)name, strlen(name));
519-
520-
yajl_gen_string(gen, (const unsigned char *)"category", 8);
521-
const char *cat = vcat ? YAJL_GET_STRING(vcat) : "";
522-
yajl_gen_string(gen, (const unsigned char *)cat, strlen(cat));
523-
524-
yajl_gen_string(gen, (const unsigned char *)"price", 5);
525-
yajl_gen_double(gen, price);
526-
527-
yajl_gen_string(gen, (const unsigned char *)"quantity", 8);
528-
yajl_gen_integer(gen, qty);
529-
530-
yajl_gen_string(gen, (const unsigned char *)"active", 6);
531-
yajl_gen_bool(gen, vactive ? YAJL_IS_TRUE(vactive) : 0);
532-
533-
yajl_gen_string(gen, (const unsigned char *)"tags", 4);
534-
yajl_gen_array_open(gen);
535-
if (vtags) {
536-
for (size_t j = 0; j < YAJL_GET_ARRAY(vtags)->len; j++) {
537-
yajl_val t = YAJL_GET_ARRAY(vtags)->values[j];
538-
if (YAJL_IS_STRING(t)) {
539-
const char *s = YAJL_GET_STRING(t);
540-
yajl_gen_string(gen, (const unsigned char *)s, strlen(s));
541-
}
542-
}
543-
}
544-
yajl_gen_array_close(gen);
545-
546-
yajl_gen_string(gen, (const unsigned char *)"rating", 6);
547-
yajl_gen_map_open(gen);
548-
if (vrating) {
549-
const char *ps[] = {"score", NULL};
550-
const char *pc[] = {"count", NULL};
551-
yajl_val vs = yajl_tree_get(vrating, ps, yajl_t_number);
552-
yajl_val vc = yajl_tree_get(vrating, pc, yajl_t_number);
553-
yajl_gen_string(gen, (const unsigned char *)"score", 5);
554-
yajl_gen_double(gen, vs ? YAJL_GET_DOUBLE(vs) : 0);
555-
yajl_gen_string(gen, (const unsigned char *)"count", 5);
556-
yajl_gen_integer(gen, vc ? YAJL_GET_INTEGER(vc) : 0);
557-
}
558-
yajl_gen_map_close(gen);
559-
560-
yajl_gen_string(gen, (const unsigned char *)"total", 5);
561-
yajl_gen_double(gen, total);
562-
563-
yajl_gen_map_close(gen);
564-
}
565-
566-
yajl_gen_array_close(gen);
567-
yajl_gen_string(gen, (const unsigned char *)"count", 5);
568-
yajl_gen_integer(gen, (long long)count);
569-
yajl_gen_map_close(gen);
570-
571-
const unsigned char *buf;
572-
size_t len;
573-
yajl_gen_get_buf(gen, &buf, &len);
574-
json_response = malloc(len);
575-
memcpy(json_response, buf, len);
576-
json_response_len = len;
577-
578-
yajl_gen_free(gen);
579-
yajl_tree_free(tree);
577+
dataset_tree = tree;
578+
dataset_count = YAJL_GET_ARRAY(tree)->len;
579+
printf("Loaded dataset: %zu items\n", dataset_count);
580580
}
581581

582582
/* Load dataset-large.json and pre-serialize the /compression response with yajl */

frameworks/hono-bun/server.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ const MIME_TYPES: Record<string, string> = {
1212
// Load datasets
1313
const datasetItems: any[] = JSON.parse(readFileSync("/data/dataset.json", "utf8"));
1414

15-
const processedItems = datasetItems.map((d: any) => ({
16-
id: d.id, name: d.name, category: d.category,
17-
price: d.price, quantity: d.quantity, active: d.active,
18-
tags: d.tags, rating: d.rating,
19-
total: Math.round(d.price * d.quantity * 100) / 100,
20-
}));
21-
const smallPayload = Buffer.from(JSON.stringify({ items: processedItems, count: processedItems.length }));
22-
2315
const largeData = JSON.parse(readFileSync("/data/dataset-large.json", "utf8"));
2416
const largeItems = largeData.map((d: any) => ({
2517
id: d.id, name: d.name, category: d.category,
@@ -108,10 +100,17 @@ app.get("/baseline2", (c) => {
108100

109101
// --- /json ---
110102
app.get("/json", (c) => {
111-
return new Response(smallPayload, {
103+
const processedItems = datasetItems.map((d: any) => ({
104+
id: d.id, name: d.name, category: d.category,
105+
price: d.price, quantity: d.quantity, active: d.active,
106+
tags: d.tags, rating: d.rating,
107+
total: Math.round(d.price * d.quantity * 100) / 100,
108+
}));
109+
const body = JSON.stringify({ items: processedItems, count: processedItems.length });
110+
return new Response(body, {
112111
headers: {
113112
"content-type": "application/json",
114-
"content-length": String(smallPayload.length),
113+
"content-length": String(Buffer.byteLength(body)),
115114
server: SERVER_NAME,
116115
},
117116
});

0 commit comments

Comments
 (0)