@@ -20,8 +20,8 @@ static h2o_globalconf_t globalconf;
2020static SSL_CTX * ssl_ctx ;
2121static __thread sqlite3 * tl_db = NULL ;
2222static __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 ;
2525static char * json_large_response ;
2626static 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 */
127127static 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 */
456554static 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 */
0 commit comments