1 /* -*- c-basic-offset: 2 -*- */
2 /*
3 Copyright(C) 2010-2014 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #ifdef HAVE_SYS_WAIT_H
31 # include <sys/wait.h>
32 #endif /* HAVE_SYS_WAIT_H */
33 #ifdef HAVE_SYS_SOCKET_H
34 # include <sys/socket.h>
35 #endif /* HAVE_SYS_SOCKET_H */
36 #ifndef WIN32
37 # include <netinet/in.h>
38 #endif /* WIN32 */
39
40 #include <grn_str.h>
41 #include <grn_com.h>
42 #include <grn_db.h>
43
44 #ifdef WIN32
45 #include <windows.h>
46 #include <stddef.h>
47 #else
48 #include <sys/param.h>
49 #include <sys/utsname.h>
50 #include <sys/statvfs.h>
51 #include <libgen.h>
52 #endif /* WIN32 */
53
54 /*
55 #define DEBUG_FTP
56 #define DEBUG_HTTP
57 */
58
59 #define FTPUSER "anonymous"
60 #define FTPPASSWD "grntest"
61 #define FTPSERVER "ftp.groonga.org"
62 #define FTPBUF 20000
63 #define DEFAULT_PORT 10041
64 #define DEFAULT_DEST "localhost"
65
66 #define OUT_JSON 0
67 #define OUT_TSV 1
68
69 static int grntest_outtype = OUT_JSON;
70
71 static grn_critical_section grntest_cs;
72
73 static int grntest_stop_flag = 0;
74 static int grntest_detail_on = 0;
75 static int grntest_remote_mode = 0;
76 static int grntest_localonly_mode = 0;
77 static int grntest_owndb_mode = 0;
78 static int grntest_onmemory_mode = 0;
79 static grn_bool grntest_ftp_mode = GRN_FALSE;
80 #define TMPFILE "_grntest.tmp"
81
82 static grn_ctx grntest_server_context;
83 static FILE *grntest_log_file;
84
85 #define OS_LINUX64 "LINUX64"
86 #define OS_LINUX32 "LINUX32"
87 #define OS_WINDOWS64 "WINDOWS64"
88 #define OS_WINDOWS32 "WINDOWS32"
89
90 #ifdef WIN32
91 typedef SOCKET socket_t;
92 #define SOCKETERROR INVALID_SOCKET
93 #define socketclose closesocket
94 static const char *groonga_path = "groonga.exe";
95 static PROCESS_INFORMATION grntest_pi;
96 #else
97 static pid_t grntest_server_id = 0;
98 typedef int socket_t;
99 #define socketclose close
100 #define SOCKETERROR -1
101 static const char *groonga_path = "groonga";
102 #endif /* WIN32 */
103
104 static const char *groonga_protocol = "gqtp";
105 static const char *grntest_osinfo;
106 static int grntest_sigint = 0;
107
108
109
110 static grn_obj *grntest_db = NULL;
111
112 #define MAX_CON_JOB 10
113 #define MAX_CON 64
114
115 #define BUF_LEN 1024
116 #define MAX_PATH_LEN 256
117
118 #define J_DO_LOCAL 1 /* do_local */
119 #define J_DO_GQTP 2 /* do_gqtp */
120 #define J_DO_HTTP 3 /* do_http */
121 #define J_REP_LOCAL 4 /* rep_local */
122 #define J_REP_GQTP 5 /* rep_gqtp */
123 #define J_REP_HTTP 6 /* rep_http */
124 #define J_OUT_LOCAL 7 /* out_local */
125 #define J_OUT_GQTP 8 /* out_gqtp */
126 #define J_OUT_HTTP 9 /* out_http */
127 #define J_TEST_LOCAL 10 /* test_local */
128 #define J_TEST_GQTP 11 /* test_gqtp */
129 #define J_TEST_HTTP 12 /* test_http */
130
131 static char grntest_username[BUF_LEN];
132 static char grntest_scriptname[BUF_LEN];
133 static char grntest_date[BUF_LEN];
134 static char grntest_serverhost[BUF_LEN];
135 static int grntest_serverport;
136 static const char *grntest_dbpath;
137
138 struct job {
139 char jobname[BUF_LEN];
140 char commandfile[BUF_LEN];
141 int qnum;
142 int jobtype;
143 int concurrency;
144 int ntimes;
145 int done;
146 long long int max;
147 long long int min;
148 FILE *outputlog;
149 grn_file_reader *inputlog;
150 char logfile[BUF_LEN];
151 };
152
153 struct task {
154 char *file;
155 grn_obj *commands;
156 int jobtype;
157 int ntimes;
158 int qnum;
159 int job_id;
160 long long int max;
161 long long int min;
162 socket_t http_socket;
163 grn_obj http_response;
164 };
165
166 static struct task grntest_task[MAX_CON];
167 static struct job grntest_job[MAX_CON];
168 static int grntest_jobdone;
169 static int grntest_jobnum;
170 static grn_ctx grntest_ctx[MAX_CON];
171 static grn_obj *grntest_owndb[MAX_CON];
172
173 static grn_obj grntest_starttime, grntest_jobs_start;
174
175 static int
grntest_atoi(const char * str,const char * end,const char ** rest)176 grntest_atoi(const char *str, const char *end, const char **rest)
177 {
178 while (grn_isspace(str, GRN_ENC_UTF8) == 1) {
179 str++;
180 }
181 return grn_atoi(str, end, rest);
182 }
183
184 static int
out_p(int jobtype)185 out_p(int jobtype)
186 {
187 if (jobtype == J_OUT_LOCAL) {
188 return 1;
189 }
190 if (jobtype == J_OUT_GQTP) {
191 return 1;
192 }
193 if (jobtype == J_OUT_HTTP) {
194 return 1;
195 }
196 return 0;
197 }
198
199 static int
test_p(int jobtype)200 test_p(int jobtype)
201 {
202 if (jobtype == J_TEST_LOCAL) {
203 return 1;
204 }
205 if (jobtype == J_TEST_GQTP) {
206 return 1;
207 }
208 if (jobtype == J_TEST_HTTP) {
209 return 1;
210 }
211 return 0;
212 }
213
214 static int
report_p(int jobtype)215 report_p(int jobtype)
216 {
217 if (jobtype == J_REP_LOCAL) {
218 return 1;
219 }
220 if (jobtype == J_REP_GQTP) {
221 return 1;
222 }
223 if (jobtype == J_REP_HTTP) {
224 return 1;
225 }
226 return 0;
227 }
228
229 static int
gqtp_p(int jobtype)230 gqtp_p(int jobtype)
231 {
232 if (jobtype == J_DO_GQTP) {
233 return 1;
234 }
235 if (jobtype == J_REP_GQTP) {
236 return 1;
237 }
238 if (jobtype == J_OUT_GQTP) {
239 return 1;
240 }
241 if (jobtype == J_TEST_GQTP) {
242 return 1;
243 }
244 return 0;
245 }
246
247 static int
http_p(int jobtype)248 http_p(int jobtype)
249 {
250 if (jobtype == J_DO_HTTP) {
251 return 1;
252 }
253 if (jobtype == J_REP_HTTP) {
254 return 1;
255 }
256 if (jobtype == J_OUT_HTTP) {
257 return 1;
258 }
259 if (jobtype == J_TEST_HTTP) {
260 return 1;
261 }
262 return 0;
263 }
264
265 static int
error_exit_in_thread(intptr_t code)266 error_exit_in_thread(intptr_t code)
267 {
268 fprintf(stderr,
269 "Fatal error! Check script file or database!: %ld\n", (long)code);
270 fflush(stderr);
271 CRITICAL_SECTION_ENTER(grntest_cs);
272 grntest_stop_flag = 1;
273 CRITICAL_SECTION_LEAVE(grntest_cs);
274 #ifdef WIN32
275 _endthreadex(code);
276 #else
277 pthread_exit((void *)code);
278 #endif /* WIN32 */
279 return 0;
280 }
281
282
283 static void
escape_command(grn_ctx * ctx,const char * in,int ilen,grn_obj * escaped_command)284 escape_command(grn_ctx *ctx, const char *in, int ilen, grn_obj *escaped_command)
285 {
286 int i = 0;
287
288 while (i < ilen) {
289 if ((in[i] == '\\') || (in[i] == '\"') || (in[i] == '/')) {
290 GRN_TEXT_PUTC(ctx, escaped_command, '\\');
291 GRN_TEXT_PUTC(ctx, escaped_command, in[i]);
292 i++;
293 } else {
294 switch (in[i]) {
295 case '\b':
296 GRN_TEXT_PUTS(ctx, escaped_command, "\\b");
297 i++;
298 break;
299 case '\f':
300 GRN_TEXT_PUTS(ctx, escaped_command, "\\f");
301 i++;
302 break;
303 case '\n':
304 GRN_TEXT_PUTS(ctx, escaped_command, "\\n");
305 i++;
306 break;
307 case '\r':
308 GRN_TEXT_PUTS(ctx, escaped_command, "\\r");
309 i++;
310 break;
311 case '\t':
312 GRN_TEXT_PUTS(ctx, escaped_command, "\\t");
313 i++;
314 break;
315 default:
316 GRN_TEXT_PUTC(ctx, escaped_command, in[i]);
317 i++;
318 break;
319 }
320 }
321 }
322 GRN_TEXT_PUTC(ctx, escaped_command, '\0');
323 }
324
325 static int
report_command(grn_ctx * ctx,const char * command,const char * ret,int task_id,grn_obj * start_time,grn_obj * end_time)326 report_command(grn_ctx *ctx, const char *command, const char *ret, int task_id,
327 grn_obj *start_time, grn_obj *end_time)
328 {
329 int i, len, clen;
330 long long int start, end;
331 grn_obj result, escaped_command;
332
333 GRN_TEXT_INIT(&result, 0);
334 if (strncmp(ret, "[[", 2) == 0) {
335 i = 2;
336 len = 1;
337 while (ret[i] != ']') {
338 i++;
339 len++;
340 if (ret[i] == '\0') {
341 fprintf(stderr, "Error results:command=[%s]\n", command);
342 error_exit_in_thread(3);
343 }
344 }
345 len++;
346 grn_text_esc(ctx, &result, ret + 1, len);
347 } else {
348 grn_text_esc(ctx, &result, ret, strlen(ret));
349 }
350
351 start = GRN_TIME_VALUE(start_time) - GRN_TIME_VALUE(&grntest_starttime);
352 end = GRN_TIME_VALUE(end_time) - GRN_TIME_VALUE(&grntest_starttime);
353 clen = strlen(command);
354 GRN_TEXT_INIT(&escaped_command, 0);
355 escape_command(ctx, command, clen, &escaped_command);
356 if (grntest_outtype == OUT_TSV) {
357 fprintf(grntest_log_file, "report\t%d\t%s\t%" GRN_FMT_LLD "\t%" GRN_FMT_LLD "\t%.*s\n",
358 task_id, GRN_TEXT_VALUE(&escaped_command), start, end,
359 (int)GRN_TEXT_LEN(&result), GRN_TEXT_VALUE(&result));
360 } else {
361 fprintf(grntest_log_file, "[%d, \"%s\", %" GRN_FMT_LLD ", %" GRN_FMT_LLD ", %.*s],\n",
362 task_id, GRN_TEXT_VALUE(&escaped_command), start, end,
363 (int)GRN_TEXT_LEN(&result), GRN_TEXT_VALUE(&result));
364 }
365 fflush(grntest_log_file);
366 GRN_OBJ_FIN(ctx, &escaped_command);
367 GRN_OBJ_FIN(ctx, &result);
368 return 0;
369 }
370
371 static int
output_result_final(grn_ctx * ctx,int qnum)372 output_result_final(grn_ctx *ctx, int qnum)
373 {
374 grn_obj end_time;
375 long long int latency, self;
376 double sec, qps;
377
378 GRN_TIME_INIT(&end_time, 0);
379 GRN_TIME_NOW(ctx, &end_time);
380
381 latency = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&grntest_starttime);
382 self = latency;
383 sec = self / (double)1000000;
384 qps = (double)qnum / sec;
385 if (grntest_outtype == OUT_TSV) {
386 fprintf(grntest_log_file, "total\t%" GRN_FMT_LLD "\t%f\t%d\n", latency, qps, qnum);
387 } else {
388 fprintf(grntest_log_file,
389 "{\"total\": %" GRN_FMT_LLD ", \"qps\": %f, \"queries\": %d}]\n", latency, qps, qnum);
390 }
391 grn_obj_close(ctx, &end_time);
392 return 0;
393 }
394
395 static int
output_sysinfo(char * sysinfo)396 output_sysinfo(char *sysinfo)
397 {
398 if (grntest_outtype == OUT_TSV) {
399 fprintf(grntest_log_file, "%s", sysinfo);
400 } else {
401 fprintf(grntest_log_file, "[%s\n", sysinfo);
402 }
403 return 0;
404 }
405
406 /* #define ENABLE_ERROR_REPORT 1 */
407 #ifdef ENABLE_ERROR_REPORT
408 static int
error_command(grn_ctx * ctx,char * command,int task_id)409 error_command(grn_ctx *ctx, char *command, int task_id)
410 {
411 fprintf(stderr, "error!:command=[%s] task_id = %d\n", command, task_id);
412 fflush(stderr);
413 error_exit_in_thread(1);
414 return 0;
415 }
416 #endif
417
418 static void
normalize_output(char * output,int length,char ** normalized_output,int * normalized_length)419 normalize_output(char *output, int length,
420 char **normalized_output, int *normalized_length)
421 {
422 int i;
423
424 *normalized_output = NULL;
425 *normalized_length = length;
426 for (i = 0; i < length; i++) {
427 if (!strncmp(output + i, "],", 2)) {
428 *normalized_output = output + i + 2;
429 *normalized_length -= i + 2;
430 break;
431 }
432 }
433
434 if (!*normalized_output) {
435 if (length > 2 && strncmp(output + length - 2, "]]", 2)) {
436 *normalized_output = output + length;
437 *normalized_length = 0;
438 } else {
439 *normalized_output = output;
440 }
441 }
442 }
443
444 static grn_bool
same_result_p(char * expect,int expected_length,char * result,int result_length)445 same_result_p(char *expect, int expected_length, char *result, int result_length)
446 {
447 char *normalized_expected, *normalized_result;
448 int normalized_expected_length, normalized_result_length;
449
450 normalize_output(expect, expected_length,
451 &normalized_expected, &normalized_expected_length);
452 normalize_output(result, result_length,
453 &normalized_result, &normalized_result_length);
454
455 return((normalized_expected_length == normalized_result_length) &&
456 strncmp(normalized_expected, normalized_result,
457 normalized_expected_length) == 0);
458 }
459
460 static socket_t
open_socket(const char * host,int port)461 open_socket(const char *host, int port)
462 {
463 socket_t sock;
464 struct hostent *servhost;
465 struct sockaddr_in server;
466 u_long inaddr;
467 int ret;
468
469 servhost = gethostbyname(host);
470 if (servhost == NULL){
471 fprintf(stderr, "Bad hostname [%s]\n", host);
472 return -1;
473 }
474 inaddr = *(u_long*)(servhost->h_addr_list[0]);
475
476 memset(&server, 0, sizeof(struct sockaddr_in));
477 server.sin_family = AF_INET;
478 server.sin_port = htons(port);
479 server.sin_addr = *(struct in_addr*)&inaddr;
480
481 sock = socket(AF_INET, SOCK_STREAM, 0);
482 if (sock == -1) {
483 fprintf(stderr, "socket error\n");
484 return -1;
485 }
486 ret = connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
487 if (ret == -1) {
488 fprintf(stderr, "connect error\n");
489 return -1;
490 }
491 return sock;
492 }
493
494 static int
write_to_server(socket_t socket,const char * buf)495 write_to_server(socket_t socket, const char *buf)
496 {
497 #ifdef DEBUG_FTP
498 fprintf(stderr, "send:%s", buf);
499 #endif
500 send(socket, buf, strlen(buf), 0);
501 return 0;
502 }
503
504 #define OUTPUT_TYPE "output_type"
505 #define OUTPUT_TYPE_LEN (sizeof(OUTPUT_TYPE) - 1)
506
507 static void
command_line_to_uri_path(grn_ctx * ctx,grn_obj * uri,const char * command)508 command_line_to_uri_path(grn_ctx *ctx, grn_obj *uri, const char *command)
509 {
510 char tok_type;
511 int offset = 0, have_key = 0;
512 const char *p, *e, *v;
513 grn_obj buf, *expr = NULL;
514 grn_expr_var *vars;
515 unsigned int nvars;
516
517 GRN_TEXT_INIT(&buf, 0);
518 p = command;
519 e = command + strlen(command);
520 p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
521 if ((expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf)))) {
522 grn_obj params, output_type;
523
524 GRN_TEXT_INIT(¶ms, 0);
525 GRN_TEXT_INIT(&output_type, 0);
526 vars = ((grn_proc *)expr)->vars;
527 nvars = ((grn_proc *)expr)->nvars;
528 GRN_TEXT_PUTS(ctx, uri, "/d/");
529 GRN_TEXT_PUT(ctx, uri, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
530 while (p < e) {
531 GRN_BULK_REWIND(&buf);
532 p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
533 v = GRN_TEXT_VALUE(&buf);
534 switch (tok_type) {
535 case GRN_TOK_VOID :
536 p = e;
537 break;
538 case GRN_TOK_SYMBOL :
539 if (GRN_TEXT_LEN(&buf) > 2 && v[0] == '-' && v[1] == '-') {
540 int l = GRN_TEXT_LEN(&buf) - 2;
541 v += 2;
542 if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
543 GRN_BULK_REWIND(&output_type);
544 p = grn_text_unesc_tok(ctx, &output_type, p, e, &tok_type);
545 break;
546 }
547 if (GRN_TEXT_LEN(¶ms)) {
548 GRN_TEXT_PUTS(ctx, ¶ms, "&");
549 }
550 grn_text_urlenc(ctx, ¶ms, v, l);
551 have_key = 1;
552 break;
553 }
554 /* fallthru */
555 case GRN_TOK_STRING :
556 case GRN_TOK_QUOTE :
557 if (!have_key) {
558 if (offset < nvars) {
559 if (GRN_TEXT_LEN(¶ms)) {
560 GRN_TEXT_PUTS(ctx, ¶ms, "&");
561 }
562 grn_text_urlenc(ctx, ¶ms,
563 vars[offset].name, vars[offset].name_size);
564 offset++;
565 }
566 }
567 GRN_TEXT_PUTS(ctx, ¶ms, "=");
568 grn_text_urlenc(ctx, ¶ms, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
569 have_key = 0;
570 break;
571 }
572 }
573 GRN_TEXT_PUTS(ctx, uri, ".");
574 if (GRN_TEXT_LEN(&output_type)) {
575 GRN_TEXT_PUT(ctx, uri,
576 GRN_TEXT_VALUE(&output_type), GRN_TEXT_LEN(&output_type));
577 } else {
578 GRN_TEXT_PUTS(ctx, uri, "json");
579 }
580 if (GRN_TEXT_LEN(¶ms) > 0) {
581 GRN_TEXT_PUTS(ctx, uri, "?");
582 GRN_TEXT_PUT(ctx, uri, GRN_TEXT_VALUE(¶ms), GRN_TEXT_LEN(¶ms));
583 }
584 GRN_OBJ_FIN(ctx, ¶ms);
585 GRN_OBJ_FIN(ctx, &output_type);
586 }
587 GRN_OBJ_FIN(ctx, &buf);
588 }
589
590 static void
command_send_http(grn_ctx * ctx,const char * command,int type,int task_id)591 command_send_http(grn_ctx *ctx, const char *command, int type, int task_id)
592 {
593 socket_t http_socket;
594 grn_obj buf;
595
596 http_socket = open_socket(grntest_serverhost, grntest_serverport);
597 if (http_socket == SOCKETERROR) {
598 fprintf(stderr, "failed to connect to groonga at %s:%d via HTTP: ",
599 grntest_serverhost, grntest_serverport);
600 #ifdef WIN32
601 fprintf(stderr, "%lu\n", GetLastError());
602 #else
603 fprintf(stderr, "%s\n", strerror(errno));
604 #endif
605 error_exit_in_thread(100);
606 }
607 grntest_task[task_id].http_socket = http_socket;
608 GRN_BULK_REWIND(&grntest_task[task_id].http_response);
609
610 GRN_TEXT_INIT(&buf, 0);
611 GRN_TEXT_PUTS(ctx, &buf, "GET ");
612 if (strncmp(command, "/d/", 3) == 0) {
613 GRN_TEXT_PUTS(ctx, &buf, command);
614 } else {
615 command_line_to_uri_path(ctx, &buf, command);
616 }
617 #ifdef DEBUG_HTTP
618 fprintf(stderr, "command: <%s>\n", command);
619 fprintf(stderr, "path: <%.*s>\n",
620 (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
621 #endif
622 GRN_TEXT_PUTS(ctx, &buf, " HTTP/1.1\r\n");
623 GRN_TEXT_PUTS(ctx, &buf, "Host: ");
624 GRN_TEXT_PUTS(ctx, &buf, grntest_serverhost);
625 GRN_TEXT_PUTS(ctx, &buf, "\r\n");
626 GRN_TEXT_PUTS(ctx, &buf, "User-Agent: grntest/");
627 GRN_TEXT_PUTS(ctx, &buf, grn_get_version());
628 GRN_TEXT_PUTS(ctx, &buf, "\r\n");
629 GRN_TEXT_PUTS(ctx, &buf, "Connection: close\r\n");
630 GRN_TEXT_PUTS(ctx, &buf, "\r\n");
631 GRN_TEXT_PUTC(ctx, &buf, '\0');
632 write_to_server(http_socket, GRN_TEXT_VALUE(&buf));
633 GRN_OBJ_FIN(ctx, &buf);
634 }
635
636 static void
command_send_ctx(grn_ctx * ctx,const char * command,int type,int task_id)637 command_send_ctx(grn_ctx *ctx, const char *command, int type, int task_id)
638 {
639 grn_ctx_send(ctx, command, strlen(command), 0);
640 /* fix me.
641 when command fails, ctx->rc is not 0 in local mode!
642 if (ctx->rc) {
643 fprintf(stderr, "ctx_send:rc=%d:command:%s\n", ctx->rc, command);
644 error_exit_in_thread(1);
645 }
646 */
647 }
648
649 static void
command_send(grn_ctx * ctx,const char * command,int type,int task_id)650 command_send(grn_ctx *ctx, const char *command, int type, int task_id)
651 {
652 if (http_p(type)) {
653 command_send_http(ctx, command, type, task_id);
654 } else {
655 command_send_ctx(ctx, command, type, task_id);
656 }
657 }
658
659 static void
command_recv_http(grn_ctx * ctx,int type,int task_id,char ** res,unsigned int * res_len,int * flags)660 command_recv_http(grn_ctx *ctx, int type, int task_id,
661 char **res, unsigned int *res_len, int *flags)
662 {
663 int len;
664 char buf[BUF_LEN];
665 char *p, *e;
666 socket_t http_socket;
667 grn_obj *http_response;
668
669 http_socket = grntest_task[task_id].http_socket;
670 http_response = &grntest_task[task_id].http_response;
671 while ((len = recv(http_socket, buf, BUF_LEN - 1, 0))) {
672 #ifdef DEBUG_HTTP
673 fprintf(stderr, "receive: <%.*s>\n", len, buf);
674 #endif
675 GRN_TEXT_PUT(ctx, http_response, buf, len);
676 }
677
678 p = GRN_TEXT_VALUE(http_response);
679 e = p + GRN_TEXT_LEN(http_response);
680 while (p < e) {
681 if (p[0] != '\r') {
682 p++;
683 continue;
684 }
685 if (e - p >= 4) {
686 if (!memcmp(p, "\r\n\r\n", 4)) {
687 *res = p + 4;
688 *res_len = e - *res;
689 #ifdef DEBUG_HTTP
690 fprintf(stderr, "body: <%.*s>\n", *res_len, *res);
691 #endif
692 break;
693 }
694 p += 4;
695 } else {
696 *res = NULL;
697 *res_len = 0;
698 break;
699 }
700 }
701
702 socketclose(http_socket);
703 grntest_task[task_id].http_socket = 0;
704 }
705
706 static void
command_recv_ctx(grn_ctx * ctx,int type,int task_id,char ** res,unsigned int * res_len,int * flags)707 command_recv_ctx(grn_ctx *ctx, int type, int task_id,
708 char **res, unsigned int *res_len, int *flags)
709 {
710 grn_ctx_recv(ctx, res, res_len, flags);
711 if (ctx->rc) {
712 fprintf(stderr, "ctx_recv:rc=%d\n", ctx->rc);
713 error_exit_in_thread(1);
714 }
715 }
716
717 static void
command_recv(grn_ctx * ctx,int type,int task_id,char ** res,unsigned int * res_len,int * flags)718 command_recv(grn_ctx *ctx, int type, int task_id,
719 char **res, unsigned int *res_len, int *flags)
720 {
721 if (http_p(type)) {
722 command_recv_http(ctx, type, task_id, res, res_len, flags);
723 } else {
724 command_recv_ctx(ctx, type, task_id, res, res_len, flags);
725 }
726 }
727
728 static int
shutdown_server(void)729 shutdown_server(void)
730 {
731 char *res;
732 int flags;
733 unsigned int res_len;
734 int job_type;
735 int task_id = 0;
736
737 if (grntest_remote_mode) {
738 return 0;
739 }
740 job_type = grntest_task[task_id].jobtype;
741 command_send(&grntest_server_context, "shutdown", job_type, task_id);
742 if (grntest_server_context.rc) {
743 fprintf(stderr, "ctx_send:rc=%d\n", grntest_server_context.rc);
744 exit(1);
745 }
746 command_recv(&grntest_server_context, job_type, task_id,
747 &res, &res_len, &flags);
748
749 return 0;
750 }
751
752 static int
do_load_command(grn_ctx * ctx,char * command,int type,int task_id,long long int * load_start)753 do_load_command(grn_ctx *ctx, char *command, int type, int task_id,
754 long long int *load_start)
755 {
756 char *res;
757 unsigned int res_len;
758 int flags, ret;
759 grn_obj start_time, end_time;
760
761 GRN_TIME_INIT(&start_time, 0);
762 if (*load_start == 0) {
763 GRN_TIME_NOW(ctx, &start_time);
764 *load_start = GRN_TIME_VALUE(&start_time);
765 } else {
766 GRN_TIME_SET(ctx, &start_time, *load_start);
767 }
768
769 command_send(ctx, command, type, task_id);
770 do {
771 command_recv(ctx, type, task_id, &res, &res_len, &flags);
772 if (res_len) {
773 long long int self;
774 GRN_TIME_INIT(&end_time, 0);
775 GRN_TIME_NOW(ctx, &end_time);
776
777 self = GRN_TIME_VALUE(&end_time) - *load_start;
778
779 if (grntest_task[task_id].max < self) {
780 grntest_task[task_id].max = self;
781 }
782 if (grntest_task[task_id].min > self) {
783 grntest_task[task_id].min = self;
784 }
785
786 if (report_p(grntest_task[task_id].jobtype)) {
787 char tmpbuf[BUF_LEN];
788
789 if (res_len < BUF_LEN) {
790 strncpy(tmpbuf, res, res_len);
791 tmpbuf[res_len] = '\0';
792 } else {
793 strncpy(tmpbuf, res, BUF_LEN - 2);
794 tmpbuf[BUF_LEN -2] = '\0';
795 }
796 report_command(ctx, "load", tmpbuf, task_id, &start_time, &end_time);
797 }
798 if (out_p(grntest_task[task_id].jobtype)) {
799 fwrite(res, 1, res_len, grntest_job[grntest_task[task_id].job_id].outputlog);
800 fputc('\n', grntest_job[grntest_task[task_id].job_id].outputlog);
801 fflush(grntest_job[grntest_task[task_id].job_id].outputlog);
802 }
803 if (test_p(grntest_task[task_id].jobtype)) {
804 grn_obj log;
805 grn_file_reader *input;
806 FILE *output;
807 GRN_TEXT_INIT(&log, 0);
808 input = grntest_job[grntest_task[task_id].job_id].inputlog;
809 output = grntest_job[grntest_task[task_id].job_id].outputlog;
810 if (grn_file_reader_read_line(ctx, input, &log) != GRN_SUCCESS) {
811 GRN_LOG(ctx, GRN_ERROR, "Cannot get input-log");
812 error_exit_in_thread(55);
813 }
814 if (GRN_TEXT_VALUE(&log)[GRN_TEXT_LEN(&log) - 1] == '\n') {
815 grn_bulk_truncate(ctx, &log, GRN_TEXT_LEN(&log) - 1);
816 }
817
818 if (!same_result_p(GRN_TEXT_VALUE(&log), GRN_TEXT_LEN(&log),
819 res, res_len)) {
820 fprintf(output, "DIFF:command:%s\n", command);
821 fprintf(output, "DIFF:result:");
822 fwrite(res, 1, res_len, output);
823 fputc('\n', output);
824 fprintf(output, "DIFF:expect:%.*s\n",
825 (int)GRN_TEXT_LEN(&log), GRN_TEXT_VALUE(&log));
826 fflush(output);
827 }
828 GRN_OBJ_FIN(ctx, &log);
829 }
830 grn_obj_close(ctx, &end_time);
831 ret = 1;
832 break;
833 } else {
834 ret = 0;
835 break;
836 }
837 } while ((flags & GRN_CTX_MORE));
838 grn_obj_close(ctx, &start_time);
839
840 return ret;
841 }
842
843
844 static int
do_command(grn_ctx * ctx,char * command,int type,int task_id)845 do_command(grn_ctx *ctx, char *command, int type, int task_id)
846 {
847 char *res;
848 unsigned int res_len;
849 int flags;
850 grn_obj start_time, end_time;
851
852 GRN_TIME_INIT(&start_time, 0);
853 GRN_TIME_NOW(ctx, &start_time);
854
855 command_send(ctx, command, type, task_id);
856 do {
857 command_recv(ctx, type, task_id, &res, &res_len, &flags);
858 if (res_len) {
859 long long int self;
860 GRN_TIME_INIT(&end_time, 0);
861 GRN_TIME_NOW(ctx, &end_time);
862
863 self = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&start_time);
864
865 if (grntest_task[task_id].max < self) {
866 grntest_task[task_id].max = self;
867 }
868 if (grntest_task[task_id].min > self) {
869 grntest_task[task_id].min = self;
870 }
871
872 if (report_p(grntest_task[task_id].jobtype)) {
873 char tmpbuf[BUF_LEN];
874
875 if (res_len < BUF_LEN) {
876 strncpy(tmpbuf, res, res_len);
877 tmpbuf[res_len] = '\0';
878 } else {
879 strncpy(tmpbuf, res, BUF_LEN - 2);
880 tmpbuf[BUF_LEN -2] = '\0';
881 }
882 report_command(ctx, command, tmpbuf, task_id, &start_time, &end_time);
883 }
884 if (out_p(grntest_task[task_id].jobtype)) {
885 fwrite(res, 1, res_len, grntest_job[grntest_task[task_id].job_id].outputlog);
886 fputc('\n', grntest_job[grntest_task[task_id].job_id].outputlog);
887 fflush(grntest_job[grntest_task[task_id].job_id].outputlog);
888 }
889 if (test_p(grntest_task[task_id].jobtype)) {
890 grn_obj log;
891 grn_file_reader *input;
892 FILE *output;
893 GRN_TEXT_INIT(&log, 0);
894 input = grntest_job[grntest_task[task_id].job_id].inputlog;
895 output = grntest_job[grntest_task[task_id].job_id].outputlog;
896 if (grn_file_reader_read_line(ctx, input, &log) != GRN_SUCCESS) {
897 GRN_LOG(ctx, GRN_ERROR, "Cannot get input-log");
898 error_exit_in_thread(55);
899 }
900 if (GRN_TEXT_VALUE(&log)[GRN_TEXT_LEN(&log) - 1] == '\n') {
901 grn_bulk_truncate(ctx, &log, GRN_TEXT_LEN(&log) - 1);
902 }
903
904 if (!same_result_p(GRN_TEXT_VALUE(&log), GRN_TEXT_LEN(&log),
905 res, res_len)) {
906 fprintf(output, "DIFF:command:%s\n", command);
907 fprintf(output, "DIFF:result:");
908 fwrite(res, 1, res_len, output);
909 fputc('\n', output);
910 fprintf(output, "DIFF:expect:%.*s\n",
911 (int)GRN_TEXT_LEN(&log), GRN_TEXT_VALUE(&log));
912 fflush(output);
913 }
914 GRN_OBJ_FIN(ctx, &log);
915 }
916 grn_obj_close(ctx, &end_time);
917 break;
918 } else {
919 #ifdef ENABLE_ERROR_REPORT
920 error_command(ctx, command, task_id);
921 #endif
922 }
923 } while ((flags & GRN_CTX_MORE));
924
925 grn_obj_close(ctx, &start_time);
926
927 return 0;
928 }
929
930 static int
comment_p(char * command)931 comment_p(char *command)
932 {
933 if (command[0] == '#') {
934 return 1;
935 }
936 return 0;
937 }
938
939 static int
load_command_p(char * command)940 load_command_p(char *command)
941 {
942 int i = 0;
943
944 while (grn_isspace(&command[i], GRN_ENC_UTF8) == 1) {
945 i++;
946 }
947 if (command[i] == '\0') {
948 return 0;
949 }
950 if (!strncmp(&command[i], "load", 4)) {
951 return 1;
952 }
953 return 0;
954 }
955
956 static int
worker_sub(grn_ctx * ctx,grn_obj * log,int task_id)957 worker_sub(grn_ctx *ctx, grn_obj *log, int task_id)
958 {
959 int i, load_mode, load_count;
960 grn_obj end_time;
961 long long int total_elapsed_time, job_elapsed_time;
962 double sec, qps;
963 long long int load_start;
964 struct task *task;
965 struct job *job;
966
967 task = &(grntest_task[task_id]);
968 task->max = 0LL;
969 task->min = 9223372036854775807LL;
970 task->qnum = 0;
971
972 for (i = 0; i < task->ntimes; i++) {
973 if (task->file != NULL) {
974 grn_file_reader *reader;
975 grn_obj line;
976 reader = grn_file_reader_open(ctx, task->file);
977 if (!reader) {
978 fprintf(stderr, "Cannot open %s\n",grntest_task[task_id].file);
979 error_exit_in_thread(1);
980 }
981 load_mode = 0;
982 load_count = 0;
983 load_start = 0LL;
984 GRN_TEXT_INIT(&line, 0);
985 while (grn_file_reader_read_line(ctx, reader, &line) == GRN_SUCCESS) {
986 if (GRN_TEXT_VALUE(&line)[GRN_TEXT_LEN(&line) - 1] == '\n') {
987 grn_bulk_truncate(ctx, &line, GRN_TEXT_LEN(&line) - 1);
988 }
989 if (GRN_TEXT_LEN(&line) == 0) {
990 GRN_BULK_REWIND(&line);
991 continue;
992 }
993 GRN_TEXT_PUTC(ctx, &line, '\0');
994 if (comment_p(GRN_TEXT_VALUE(&line))) {
995 GRN_BULK_REWIND(&line);
996 continue;
997 }
998 if (load_command_p(GRN_TEXT_VALUE(&line))) {
999 load_mode = 1;
1000 load_count = 1;
1001 }
1002 if (load_mode == 1) {
1003 if (do_load_command(&grntest_ctx[task_id], GRN_TEXT_VALUE(&line),
1004 task->jobtype,
1005 task_id, &load_start)) {
1006 task->qnum += load_count;
1007 load_mode = 0;
1008 load_count = 0;
1009 load_start = 0LL;
1010 }
1011 load_count++;
1012 GRN_BULK_REWIND(&line);
1013 continue;
1014 }
1015 do_command(&grntest_ctx[task_id], GRN_TEXT_VALUE(&line),
1016 task->jobtype,
1017 task_id);
1018 task->qnum++;
1019 GRN_BULK_REWIND(&line);
1020 if (grntest_sigint) {
1021 goto exit;
1022 }
1023 }
1024 GRN_OBJ_FIN(ctx, &line);
1025 grn_file_reader_close(ctx, reader);
1026 } else {
1027 int i, n_commands;
1028 grn_obj *commands;
1029 commands = task->commands;
1030 if (!commands) {
1031 error_exit_in_thread(1);
1032 }
1033 load_mode = 0;
1034 n_commands = GRN_BULK_VSIZE(commands) / sizeof(grn_obj *);
1035 for (i = 0; i < n_commands; i++) {
1036 grn_obj *command;
1037 command = GRN_PTR_VALUE_AT(commands, i);
1038 if (load_command_p(GRN_TEXT_VALUE(command))) {
1039 load_mode = 1;
1040 }
1041 if (load_mode == 1) {
1042 if (do_load_command(&grntest_ctx[task_id],
1043 GRN_TEXT_VALUE(command),
1044 task->jobtype, task_id, &load_start)) {
1045 load_mode = 0;
1046 load_start = 0LL;
1047 task->qnum++;
1048 }
1049 continue;
1050 }
1051 do_command(&grntest_ctx[task_id],
1052 GRN_TEXT_VALUE(command),
1053 task->jobtype, task_id);
1054 task->qnum++;
1055 if (grntest_sigint) {
1056 goto exit;
1057 }
1058 }
1059 }
1060 }
1061
1062 exit:
1063 GRN_TIME_INIT(&end_time, 0);
1064 GRN_TIME_NOW(&grntest_ctx[task_id], &end_time);
1065 total_elapsed_time = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&grntest_starttime);
1066 job_elapsed_time = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&grntest_jobs_start);
1067
1068 CRITICAL_SECTION_ENTER(grntest_cs);
1069 job = &(grntest_job[task->job_id]);
1070 if (job->max < task->max) {
1071 job->max = task->max;
1072 }
1073 if (job->min > task->min) {
1074 job->min = task->min;
1075 }
1076
1077 job->qnum += task->qnum;
1078 job->done++;
1079 if (job->done == job->concurrency) {
1080 char tmpbuf[BUF_LEN];
1081 sec = job_elapsed_time / (double)1000000;
1082 qps = (double)job->qnum/ sec;
1083 grntest_jobdone++;
1084 if (grntest_outtype == OUT_TSV) {
1085 sprintf(tmpbuf,
1086 "job\t"
1087 "%s\t"
1088 "%" GRN_FMT_LLD "\t"
1089 "%" GRN_FMT_LLD "\t"
1090 "%f\t"
1091 "%" GRN_FMT_LLD "\t"
1092 "%" GRN_FMT_LLD "\t"
1093 "%d\n",
1094 job->jobname,
1095 total_elapsed_time,
1096 job_elapsed_time,
1097 qps,
1098 job->min,
1099 job->max,
1100 job->qnum);
1101 } else {
1102 sprintf(tmpbuf,
1103 "{\"job\": \"%s\", "
1104 "\"total_elapsed_time\": %" GRN_FMT_LLD ", "
1105 "\"job_elapsed_time\": %" GRN_FMT_LLD ", "
1106 "\"qps\": %f, "
1107 "\"min\": %" GRN_FMT_LLD ", "
1108 "\"max\": %" GRN_FMT_LLD ", "
1109 "\"queries\": %d}",
1110 job->jobname,
1111 total_elapsed_time,
1112 job_elapsed_time,
1113 qps,
1114 job->min,
1115 job->max,
1116 job->qnum);
1117 if (grntest_jobdone < grntest_jobnum) {
1118 grn_strcat(tmpbuf, BUF_LEN, ",");
1119 }
1120 }
1121 GRN_TEXT_PUTS(ctx, log, tmpbuf);
1122 if (grntest_jobdone == grntest_jobnum) {
1123 if (grntest_outtype == OUT_TSV) {
1124 fprintf(grntest_log_file, "%.*s",
1125 (int)GRN_TEXT_LEN(log), GRN_TEXT_VALUE(log));
1126 } else {
1127 if (grntest_detail_on) {
1128 fseek(grntest_log_file, -2, SEEK_CUR);
1129 fprintf(grntest_log_file, "],\n");
1130 }
1131 fprintf(grntest_log_file, "\"summary\": [");
1132 fprintf(grntest_log_file, "%.*s",
1133 (int)GRN_TEXT_LEN(log), GRN_TEXT_VALUE(log));
1134 fprintf(grntest_log_file, "]");
1135 }
1136 fflush(grntest_log_file);
1137 }
1138 }
1139 grn_obj_close(&grntest_ctx[task_id], &end_time);
1140 CRITICAL_SECTION_LEAVE(grntest_cs);
1141
1142 return 0;
1143 }
1144
1145 typedef struct _grntest_worker {
1146 grn_ctx *ctx;
1147 grn_obj log;
1148 int task_id;
1149 } grntest_worker;
1150
1151 #ifdef WIN32
1152 static unsigned int
1153 __stdcall
worker(void * val)1154 worker(void *val)
1155 {
1156 grntest_worker *worker = val;
1157 worker_sub(worker->ctx, &worker->log, worker->task_id);
1158 return 0;
1159 }
1160 #else
1161 static void *
worker(void * val)1162 worker(void *val)
1163 {
1164 grntest_worker *worker = val;
1165 worker_sub(worker->ctx, &worker->log, worker->task_id);
1166 return NULL;
1167 }
1168 #endif /* WIN32 */
1169
1170 #ifdef WIN32
1171 static int
thread_main(grn_ctx * ctx,int num)1172 thread_main(grn_ctx *ctx, int num)
1173 {
1174 int i;
1175 int ret;
1176 HANDLE pthread[MAX_CON];
1177 grntest_worker *workers[MAX_CON];
1178
1179 for (i = 0; i < num; i++) {
1180 workers[i] = GRN_MALLOC(sizeof(grntest_worker));
1181 workers[i]->ctx = &grntest_ctx[i];
1182 GRN_TEXT_INIT(&workers[i]->log, 0);
1183 workers[i]->task_id = i;
1184 pthread[i] = (HANDLE)_beginthreadex(NULL, 0, worker, (void *)workers[i],
1185 0, NULL);
1186 if (pthread[i]== (HANDLE)0) {
1187 fprintf(stderr, "thread failed:%d\n", i);
1188 error_exit_in_thread(1);
1189 }
1190 }
1191
1192 ret = WaitForMultipleObjects(num, pthread, TRUE, INFINITE);
1193 if (ret == WAIT_TIMEOUT) {
1194 fprintf(stderr, "timeout\n");
1195 error_exit_in_thread(1);
1196 }
1197
1198 for (i = 0; i < num; i++) {
1199 CloseHandle(pthread[i]);
1200 GRN_OBJ_FIN(workers[i]->ctx, &workers[i]->log);
1201 GRN_FREE(workers[i]);
1202 }
1203 return 0;
1204 }
1205 #else
1206 static int
thread_main(grn_ctx * ctx,int num)1207 thread_main(grn_ctx *ctx, int num)
1208 {
1209 intptr_t i;
1210 int ret;
1211 pthread_t pthread[MAX_CON];
1212 grntest_worker *workers[MAX_CON];
1213
1214 for (i = 0; i < num; i++) {
1215 workers[i] = GRN_MALLOC(sizeof(grntest_worker));
1216 workers[i]->ctx = &grntest_ctx[i];
1217 GRN_TEXT_INIT(&workers[i]->log, 0);
1218 workers[i]->task_id = i;
1219 ret = pthread_create(&pthread[i], NULL, worker, (void *)workers[i]);
1220 if (ret) {
1221 fprintf(stderr, "Cannot create thread:ret=%d\n", ret);
1222 error_exit_in_thread(1);
1223 }
1224 }
1225
1226 for (i = 0; i < num; i++) {
1227 ret = pthread_join(pthread[i], NULL);
1228 GRN_OBJ_FIN(workers[i]->ctx, &workers[i]->log);
1229 GRN_FREE(workers[i]);
1230 if (ret) {
1231 fprintf(stderr, "Cannot join thread:ret=%d\n", ret);
1232 error_exit_in_thread(1);
1233 }
1234 }
1235 return 0;
1236 }
1237 #endif
1238
1239 static int
error_exit(grn_ctx * ctx,int ret)1240 error_exit(grn_ctx *ctx, int ret)
1241 {
1242 fflush(stderr);
1243 shutdown_server();
1244 grn_ctx_fin(ctx);
1245 grn_fin();
1246 exit(ret);
1247 }
1248
1249 static int
get_sysinfo(const char * path,char * result,int olen)1250 get_sysinfo(const char *path, char *result, int olen)
1251 {
1252 char tmpbuf[256];
1253
1254 #ifdef WIN32
1255 ULARGE_INTEGER dinfo;
1256 char cpustring[64];
1257 SYSTEM_INFO sinfo;
1258 MEMORYSTATUSEX minfo;
1259 OSVERSIONINFO osinfo;
1260
1261 if (grntest_outtype == OUT_TSV) {
1262 result[0] = '\0';
1263 sprintf(tmpbuf, "script\t%s\n", grntest_scriptname);
1264 grn_strcat(result, olen, tmpbuf);
1265 sprintf(tmpbuf, "user\t%s\n", grntest_username);
1266 grn_strcat(result, olen, tmpbuf);
1267 sprintf(tmpbuf, "date\t%s\n", grntest_date);
1268 grn_strcat(result, olen, tmpbuf);
1269 } else {
1270 grn_strcpy(result, olen, "{");
1271 sprintf(tmpbuf, "\"script\": \"%s.scr\",\n", grntest_scriptname);
1272 grn_strcat(result, olen, tmpbuf);
1273 sprintf(tmpbuf, " \"user\": \"%s\",\n", grntest_username);
1274 grn_strcat(result, olen, tmpbuf);
1275 sprintf(tmpbuf, " \"date\": \"%s\",\n", grntest_date);
1276 grn_strcat(result, olen, tmpbuf);
1277 }
1278
1279 memset(cpustring, 0, 64);
1280 #ifndef __GNUC__
1281 {
1282 int cinfo[4];
1283 __cpuid(cinfo, 0x80000002);
1284 memcpy(cpustring, cinfo, 16);
1285 __cpuid(cinfo, 0x80000003);
1286 memcpy(cpustring+16, cinfo, 16);
1287 __cpuid(cinfo, 0x80000004);
1288 memcpy(cpustring+32, cinfo, 16);
1289 }
1290 #endif
1291
1292 if (grntest_outtype == OUT_TSV) {
1293 sprintf(tmpbuf, "%s\n", cpustring);
1294 } else {
1295 sprintf(tmpbuf, " \"CPU\": \"%s\",\n", cpustring);
1296 }
1297 grn_strcat(result, olen, tmpbuf);
1298
1299 if (sizeof(int *) == 8) {
1300 grntest_osinfo = OS_WINDOWS64;
1301 if (grntest_outtype == OUT_TSV) {
1302 sprintf(tmpbuf, "64BIT\n");
1303 } else {
1304 sprintf(tmpbuf, " \"BIT\": 64,\n");
1305 }
1306 } else {
1307 grntest_osinfo = OS_WINDOWS32;
1308 if (grntest_outtype == OUT_TSV) {
1309 sprintf(tmpbuf, "32BIT\n");
1310 } else {
1311 sprintf(tmpbuf, " \"BIT\": 32,\n");
1312 }
1313 }
1314 grn_strcat(result, olen, tmpbuf);
1315
1316 GetSystemInfo(&sinfo);
1317 if (grntest_outtype == OUT_TSV) {
1318 sprintf(tmpbuf, "CORE\t%lu\n", sinfo.dwNumberOfProcessors);
1319 } else {
1320 sprintf(tmpbuf, " \"CORE\": %lu,\n", sinfo.dwNumberOfProcessors);
1321 }
1322 grn_strcat(result, olen, tmpbuf);
1323
1324 minfo.dwLength = sizeof(MEMORYSTATUSEX);
1325 GlobalMemoryStatusEx(&minfo);
1326 if (grntest_outtype == OUT_TSV) {
1327 sprintf(tmpbuf, "RAM\t%I64dMByte\n", minfo.ullTotalPhys/(1024*1024));
1328 } else {
1329 sprintf(tmpbuf, " \"RAM\": \"%I64dMByte\",\n", minfo.ullTotalPhys/(1024*1024));
1330 }
1331 grn_strcat(result, olen, tmpbuf);
1332
1333 GetDiskFreeSpaceEx(NULL, NULL, &dinfo, NULL);
1334 if (grntest_outtype == OUT_TSV) {
1335 sprintf(tmpbuf, "HDD\t%I64dKBytes\n", dinfo.QuadPart/1024 );
1336 } else {
1337 sprintf(tmpbuf, " \"HDD\": \"%I64dKBytes\",\n", dinfo.QuadPart/1024 );
1338 }
1339 grn_strcat(result, olen, tmpbuf);
1340
1341 osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osinfo);
1342 if (grntest_outtype == OUT_TSV) {
1343 sprintf(tmpbuf, "Windows %ld.%ld\n",
1344 osinfo.dwMajorVersion, osinfo.dwMinorVersion);
1345 } else {
1346 sprintf(tmpbuf, " \"OS\": \"Windows %lu.%lu\",\n", osinfo.dwMajorVersion,
1347 osinfo.dwMinorVersion);
1348 }
1349 grn_strcat(result, olen, tmpbuf);
1350
1351 if (grntest_outtype == OUT_TSV) {
1352 sprintf(tmpbuf, "%s\n", grntest_serverhost);
1353 } else {
1354 sprintf(tmpbuf, " \"HOST\": \"%s\",\n", grntest_serverhost);
1355 }
1356 grn_strcat(result, olen, tmpbuf);
1357
1358 if (grntest_outtype == OUT_TSV) {
1359 sprintf(tmpbuf, "%d\n", grntest_serverport);
1360 } else {
1361 sprintf(tmpbuf, " \"PORT\": \"%d\",\n", grntest_serverport);
1362 }
1363 grn_strcat(result, olen, tmpbuf);
1364
1365 if (grntest_outtype == OUT_TSV) {
1366 sprintf(tmpbuf, "%s\"\n", grn_get_version());
1367 } else {
1368 sprintf(tmpbuf, " \"VERSION\": \"%s\"\n", grn_get_version());
1369 }
1370
1371 grn_strcat(result, olen, tmpbuf);
1372 if (grntest_outtype != OUT_TSV) {
1373 grn_strcat(result, olen, "}");
1374 }
1375
1376 #else /* linux only */
1377 FILE *fp;
1378 int ret;
1379 int cpunum = 0;
1380 int minfo = 0;
1381 int unevictable = 0;
1382 int mlocked = 0;
1383 #define CPU_STRING_SIZE 256
1384 char cpu_string[CPU_STRING_SIZE];
1385 struct utsname ubuf;
1386 struct statvfs vfsbuf;
1387
1388 if (grntest_outtype == OUT_TSV) {
1389 result[0] = '\0';
1390 sprintf(tmpbuf, "sctipt\t%s\n", grntest_scriptname);
1391 grn_strcat(result, olen, tmpbuf);
1392 sprintf(tmpbuf, "user\t%s\n", grntest_username);
1393 grn_strcat(result, olen, tmpbuf);
1394 sprintf(tmpbuf, "date\t%s\n", grntest_date);
1395 grn_strcat(result, olen, tmpbuf);
1396 } else {
1397 grn_strcpy(result, olen, "{");
1398 sprintf(tmpbuf, "\"script\": \"%s.scr\",\n", grntest_scriptname);
1399 grn_strcat(result, olen, tmpbuf);
1400 sprintf(tmpbuf, " \"user\": \"%s\",\n", grntest_username);
1401 grn_strcat(result, olen, tmpbuf);
1402 sprintf(tmpbuf, " \"date\": \"%s\",\n", grntest_date);
1403 grn_strcat(result, olen, tmpbuf);
1404 }
1405
1406 fp = fopen("/proc/cpuinfo", "r");
1407 if (!fp) {
1408 fprintf(stderr, "Cannot open cpuinfo\n");
1409 exit(1);
1410 }
1411 while (fgets(tmpbuf, 256, fp) != NULL) {
1412 tmpbuf[strlen(tmpbuf)-1] = '\0';
1413 if (!strncmp(tmpbuf, "model name\t: ", 13)) {
1414 grn_strcpy(cpu_string, CPU_STRING_SIZE, &tmpbuf[13]);
1415 }
1416 }
1417 fclose(fp);
1418 #undef CPU_STRING_SIZE
1419
1420 cpunum = sysconf(_SC_NPROCESSORS_CONF);
1421
1422 if (grntest_outtype == OUT_TSV) {
1423 sprintf(tmpbuf, "%s\n", cpu_string);
1424 } else {
1425 sprintf(tmpbuf, " \"CPU\": \"%s\",\n", cpu_string);
1426 }
1427 grn_strcat(result, olen, tmpbuf);
1428
1429 if (sizeof(int *) == 8) {
1430 grntest_osinfo = OS_LINUX64;
1431 if (grntest_outtype == OUT_TSV) {
1432 sprintf(tmpbuf, "64BIT\n");
1433 } else {
1434 sprintf(tmpbuf, " \"BIT\": 64,\n");
1435 }
1436 } else {
1437 grntest_osinfo = OS_LINUX32;
1438 if (grntest_outtype == OUT_TSV) {
1439 sprintf(tmpbuf, "32BIT\n");
1440 } else {
1441 sprintf(tmpbuf, " \"BIT\": 32,\n");
1442 }
1443 }
1444 grn_strcat(result, olen, tmpbuf);
1445
1446 if (grntest_outtype == OUT_TSV) {
1447 sprintf(tmpbuf, "CORE\t%d\n", cpunum);
1448 } else {
1449 sprintf(tmpbuf, " \"CORE\": %d,\n", cpunum);
1450 }
1451 grn_strcat(result, olen, tmpbuf);
1452
1453 fp = fopen("/proc/meminfo", "r");
1454 if (!fp) {
1455 fprintf(stderr, "Cannot open meminfo\n");
1456 exit(1);
1457 }
1458 while (fgets(tmpbuf, 256, fp) != NULL) {
1459 tmpbuf[strlen(tmpbuf)-1] = '\0';
1460 if (!strncmp(tmpbuf, "MemTotal:", 9)) {
1461 minfo = grntest_atoi(&tmpbuf[10], &tmpbuf[10] + 40, NULL);
1462 }
1463 if (!strncmp(tmpbuf, "Unevictable:", 12)) {
1464 unevictable = grntest_atoi(&tmpbuf[13], &tmpbuf[13] + 40, NULL);
1465 }
1466 if (!strncmp(tmpbuf, "Mlocked:", 8)) {
1467 mlocked = grntest_atoi(&tmpbuf[9], &tmpbuf[9] + 40, NULL);
1468 }
1469 }
1470 fclose(fp);
1471 if (grntest_outtype == OUT_TSV) {
1472 sprintf(tmpbuf, "%dMBytes\n", minfo/1024);
1473 grn_strcat(result, olen, tmpbuf);
1474 sprintf(tmpbuf, "%dMBytes_Unevictable\n", unevictable/1024);
1475 grn_strcat(result, olen, tmpbuf);
1476 sprintf(tmpbuf, "%dMBytes_Mlocked\n", mlocked/1024);
1477 grn_strcat(result, olen, tmpbuf);
1478 } else {
1479 sprintf(tmpbuf, " \"RAM\": \"%dMBytes\",\n", minfo/1024);
1480 grn_strcat(result, olen, tmpbuf);
1481 sprintf(tmpbuf, " \"Unevictable\": \"%dMBytes\",\n", unevictable/1024);
1482 grn_strcat(result, olen, tmpbuf);
1483 sprintf(tmpbuf, " \"Mlocked\": \"%dMBytes\",\n", mlocked/1024);
1484 grn_strcat(result, olen, tmpbuf);
1485 }
1486
1487 ret = statvfs(path, &vfsbuf);
1488 if (ret) {
1489 fprintf(stderr, "Cannot access %s\n", path);
1490 exit(1);
1491 }
1492
1493 if (grntest_outtype == OUT_TSV) {
1494 sprintf(tmpbuf, "%" GRN_FMT_INT64U "KBytes\n", vfsbuf.f_blocks * 4);
1495 } else {
1496 sprintf(tmpbuf,
1497 " \"HDD\": \"%" GRN_FMT_INT64U "KBytes\",\n",
1498 vfsbuf.f_blocks * 4);
1499 }
1500 grn_strcat(result, olen, tmpbuf);
1501
1502 uname(&ubuf);
1503 if (grntest_outtype == OUT_TSV) {
1504 sprintf(tmpbuf, "%s %s\n", ubuf.sysname, ubuf.release);
1505 } else {
1506 sprintf(tmpbuf, " \"OS\": \"%s %s\",\n", ubuf.sysname, ubuf.release);
1507 }
1508 grn_strcat(result, olen, tmpbuf);
1509
1510 if (grntest_outtype == OUT_TSV) {
1511 sprintf(tmpbuf, "%s\n", grntest_serverhost);
1512 } else {
1513 sprintf(tmpbuf, " \"HOST\": \"%s\",\n", grntest_serverhost);
1514 }
1515 grn_strcat(result, olen, tmpbuf);
1516
1517 if (grntest_outtype == OUT_TSV) {
1518 sprintf(tmpbuf, "%d\n", grntest_serverport);
1519 } else {
1520 sprintf(tmpbuf, " \"PORT\": \"%d\",\n", grntest_serverport);
1521 }
1522 grn_strcat(result, olen, tmpbuf);
1523
1524 if (grntest_outtype == OUT_TSV) {
1525 sprintf(tmpbuf, "%s\n", grn_get_version());
1526 } else {
1527 sprintf(tmpbuf, " \"VERSION\": \"%s\"\n", grn_get_version());
1528 }
1529 grn_strcat(result, olen, tmpbuf);
1530
1531 if (grntest_outtype != OUT_TSV) {
1532 grn_strcat(result, olen, "},");
1533 }
1534 #endif /* WIN32 */
1535 if (strlen(result) >= olen) {
1536 fprintf(stderr, "buffer overrun in get_sysinfo!\n");
1537 exit(1);
1538 }
1539 return 0;
1540 }
1541
1542 static int
start_server(const char * dbpath,int r)1543 start_server(const char *dbpath, int r)
1544 {
1545 int ret;
1546 char optbuf[BUF_LEN];
1547 #ifdef WIN32
1548 char tmpbuf[BUF_LEN];
1549
1550 STARTUPINFO si;
1551
1552 if (strlen(dbpath) > BUF_LEN - 100) {
1553 fprintf(stderr, "too long dbpath!\n");
1554 exit(1);
1555 }
1556
1557 grn_strcpy(tmpbuf, BUF_LEN, groonga_path);
1558 grn_strcat(tmpbuf, BUF_LEN, " -s --protocol ");
1559 grn_strcat(tmpbuf, BUF_LEN, groonga_protocol);
1560 grn_strcat(tmpbuf, BUF_LEN, " -p ");
1561 sprintf(optbuf, "%d ", grntest_serverport);
1562 grn_strcat(tmpbuf, BUF_LEN, optbuf);
1563 grn_strcat(tmpbuf, BUF_LEN, dbpath);
1564 memset(&si, 0, sizeof(STARTUPINFO));
1565 si.cb=sizeof(STARTUPINFO);
1566 ret = CreateProcess(NULL, tmpbuf, NULL, NULL, FALSE,
1567 0, NULL, NULL, &si, &grntest_pi);
1568
1569 if (ret == 0) {
1570 fprintf(stderr, "Cannot start groonga server: <%s>: error=%lu\n",
1571 groonga_path, GetLastError());
1572 exit(1);
1573 }
1574
1575 #else
1576 pid_t pid;
1577 pid = fork();
1578 if (pid < 0) {
1579 fprintf(stderr, "Cannot start groonga server:Cannot fork\n");
1580 exit(1);
1581 }
1582 sprintf(optbuf, "%d", grntest_serverport);
1583 if (pid == 0) {
1584 ret = execlp(groonga_path, groonga_path,
1585 "-s",
1586 "--protocol", groonga_protocol,
1587 "-p", optbuf,
1588 dbpath, (char*)NULL);
1589 if (ret == -1) {
1590 fprintf(stderr, "Cannot start groonga server: <%s>: errno=%d\n",
1591 groonga_path, errno);
1592 exit(1);
1593 }
1594 }
1595 else {
1596 grntest_server_id = pid;
1597 }
1598
1599 #endif /* WIN32 */
1600
1601 return 0;
1602 }
1603
1604 static int
parse_line(grn_ctx * ctx,char * buf,int start,int end,int num)1605 parse_line(grn_ctx *ctx, char *buf, int start, int end, int num)
1606 {
1607 int i, j, error_flag = 0, out_or_test = 0;
1608 char tmpbuf[BUF_LEN];
1609
1610 grntest_job[num].concurrency = 1;
1611 grntest_job[num].ntimes = 1;
1612 grntest_job[num].done = 0;
1613 grntest_job[num].qnum = 0;
1614 grntest_job[num].max = 0LL;
1615 grntest_job[num].min = 9223372036854775807LL;
1616 grntest_job[num].outputlog = NULL;
1617 grntest_job[num].inputlog = NULL;
1618
1619 strncpy(grntest_job[num].jobname, &buf[start], end - start);
1620 grntest_job[num].jobname[end - start] = '\0';
1621 i = start;
1622 while (i < end) {
1623 if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1624 i++;
1625 continue;
1626 }
1627 if (!strncmp(&buf[i], "do_local", 8)) {
1628 grntest_job[num].jobtype = J_DO_LOCAL;
1629 i = i + 8;
1630 break;
1631 }
1632 if (!strncmp(&buf[i], "do_gqtp", 7)) {
1633 grntest_job[num].jobtype = J_DO_GQTP;
1634 i = i + 7;
1635 break;
1636 }
1637 if (!strncmp(&buf[i], "do_http", 7)) {
1638 grntest_job[num].jobtype = J_DO_HTTP;
1639 i = i + 7;
1640 break;
1641 }
1642 if (!strncmp(&buf[i], "rep_local", 9)) {
1643 grntest_job[num].jobtype = J_REP_LOCAL;
1644 i = i + 9;
1645 break;
1646 }
1647 if (!strncmp(&buf[i], "rep_gqtp", 8)) {
1648 grntest_job[num].jobtype = J_REP_GQTP;
1649 i = i + 8;
1650 break;
1651 }
1652 if (!strncmp(&buf[i], "rep_http", 8)) {
1653 grntest_job[num].jobtype = J_REP_HTTP;
1654 i = i + 8;
1655 break;
1656 }
1657 if (!strncmp(&buf[i], "out_local", 9)) {
1658 grntest_job[num].jobtype = J_OUT_LOCAL;
1659 i = i + 9;
1660 out_or_test = 1;
1661 break;
1662 }
1663 if (!strncmp(&buf[i], "out_gqtp", 8)) {
1664 grntest_job[num].jobtype = J_OUT_GQTP;
1665 i = i + 8;
1666 out_or_test = 1;
1667 break;
1668 }
1669 if (!strncmp(&buf[i], "out_http", 8)) {
1670 grntest_job[num].jobtype = J_OUT_HTTP;
1671 i = i + 8;
1672 out_or_test = 1;
1673 break;
1674 }
1675 if (!strncmp(&buf[i], "test_local", 10)) {
1676 grntest_job[num].jobtype = J_TEST_LOCAL;
1677 i = i + 10;
1678 out_or_test = 1;
1679 break;
1680 }
1681 if (!strncmp(&buf[i], "test_gqtp", 9)) {
1682 grntest_job[num].jobtype = J_TEST_GQTP;
1683 i = i + 9;
1684 out_or_test = 1;
1685 break;
1686 }
1687 if (!strncmp(&buf[i], "test_http", 9)) {
1688 grntest_job[num].jobtype = J_TEST_HTTP;
1689 i = i + 9;
1690 out_or_test = 1;
1691 break;
1692 }
1693 error_flag = 1;
1694 i++;
1695 }
1696
1697 if (error_flag) {
1698 return 3;
1699 }
1700 if (i == end) {
1701 return 1;
1702 }
1703
1704 if (grn_isspace(&buf[i], GRN_ENC_UTF8) != 1) {
1705 return 4;
1706 }
1707 i++;
1708
1709 while (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1710 i++;
1711 continue;
1712 }
1713 j = 0;
1714 while (i < end) {
1715 if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1716 break;
1717 }
1718 grntest_job[num].commandfile[j] = buf[i];
1719 i++;
1720 j++;
1721 if (j > 255) {
1722 return 5;
1723 }
1724 }
1725 grntest_job[num].commandfile[j] = '\0';
1726
1727 while (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1728 i++;
1729 }
1730
1731 if (i == end) {
1732 if (out_or_test) {
1733 fprintf(stderr, "log(test)_local(gqtp|http) needs log(test)_filename\n");
1734 return 11;
1735 }
1736 return 0;
1737 }
1738
1739 j = 0;
1740 while (i < end) {
1741 if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1742 break;
1743 }
1744 tmpbuf[j] = buf[i];
1745 i++;
1746 j++;
1747 if (j >= BUF_LEN) {
1748 return 6;
1749 }
1750 }
1751 tmpbuf[j] ='\0';
1752 if (out_or_test) {
1753 if (out_p(grntest_job[num].jobtype)) {
1754 grntest_job[num].outputlog = fopen(tmpbuf, "wb");
1755 if (grntest_job[num].outputlog == NULL) {
1756 fprintf(stderr, "Cannot open %s\n", tmpbuf);
1757 return 13;
1758 }
1759 } else {
1760 char outlog[BUF_LEN];
1761 grntest_job[num].inputlog = grn_file_reader_open(ctx, tmpbuf);
1762 if (grntest_job[num].inputlog == NULL) {
1763 fprintf(stderr, "Cannot open %s\n", tmpbuf);
1764 return 14;
1765 }
1766 sprintf(outlog, "%s.diff", tmpbuf);
1767 grntest_job[num].outputlog = fopen(outlog, "wb");
1768 if (grntest_job[num].outputlog == NULL) {
1769 fprintf(stderr, "Cannot open %s\n", outlog);
1770 return 15;
1771 }
1772 }
1773 grn_strcpy(grntest_job[num].logfile, BUF_LEN, tmpbuf);
1774 return 0;
1775 } else {
1776 grntest_job[num].concurrency = grntest_atoi(tmpbuf, tmpbuf + j, NULL);
1777 if (grntest_job[num].concurrency == 0) {
1778 return 7;
1779 }
1780 }
1781
1782 while (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1783 i++;
1784 }
1785
1786 if (i == end) {
1787 return 0;
1788 }
1789
1790 j = 0;
1791 while (i < end) {
1792 if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1793 break;
1794 }
1795 tmpbuf[j] = buf[i];
1796 i++;
1797 j++;
1798 if (j > 16) {
1799 return 8;
1800 }
1801 }
1802 tmpbuf[j] ='\0';
1803 grntest_job[num].ntimes = grntest_atoi(tmpbuf, tmpbuf + j, NULL);
1804 if (grntest_job[num].ntimes == 0) {
1805 return 9;
1806 }
1807 if (i == end) {
1808 return 0;
1809 }
1810
1811 while (i < end) {
1812 if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
1813 i++;
1814 continue;
1815 }
1816 return 10;
1817 }
1818 return 0;
1819 }
1820
1821 static int
get_jobs(grn_ctx * ctx,char * buf,int line)1822 get_jobs(grn_ctx *ctx, char *buf, int line)
1823 {
1824 int i, len, start, end, ret;
1825 int jnum = 0;
1826
1827 len = strlen(buf);
1828 i = 0;
1829 while (i < len) {
1830 if ((buf[i] == '#') || (buf[i] == '\r') || (buf[i] == '\n')) {
1831 buf[i] = '\0';
1832 len = i;
1833 break;
1834 }
1835 i++;
1836 }
1837
1838 i = 0;
1839 start = 0;
1840 while (i < len) {
1841 if (buf[i] == ';') {
1842 end = i;
1843 ret = parse_line(ctx, buf, start, end, jnum);
1844 if (ret) {
1845 if (ret > 1) {
1846 fprintf(stderr, "Syntax error:line=%d:ret=%d:%s\n", line, ret, buf);
1847 error_exit(ctx, 1);
1848 }
1849 } else {
1850 jnum++;
1851 }
1852 start = end + 1;
1853 }
1854 i++;
1855 }
1856 end = len;
1857 ret = parse_line(ctx, buf, start, end, jnum);
1858 if (ret) {
1859 if (ret > 1) {
1860 fprintf(stderr, "Syntax error:line=%d:ret=%d:%s\n", line, ret, buf);
1861 error_exit(ctx, 1);
1862 }
1863 } else {
1864 jnum++;
1865 }
1866 return jnum;
1867 }
1868
1869 static int
make_task_table(grn_ctx * ctx,int jobnum)1870 make_task_table(grn_ctx *ctx, int jobnum)
1871 {
1872 int i, j;
1873 int tid = 0;
1874 grn_obj *commands = NULL;
1875
1876 for (i = 0; i < jobnum; i++) {
1877 if ((grntest_job[i].concurrency == 1) && (!grntest_onmemory_mode)) {
1878 grntest_task[tid].file = grntest_job[i].commandfile;
1879 grntest_task[tid].commands = NULL;
1880 grntest_task[tid].ntimes = grntest_job[i].ntimes;
1881 grntest_task[tid].jobtype = grntest_job[i].jobtype;
1882 grntest_task[tid].job_id = i;
1883 tid++;
1884 continue;
1885 }
1886 for (j = 0; j < grntest_job[i].concurrency; j++) {
1887 if (j == 0) {
1888 grn_file_reader *reader;
1889 grn_obj line;
1890 GRN_TEXT_INIT(&line, 0);
1891 commands = grn_obj_open(ctx, GRN_PVECTOR, 0, GRN_VOID);
1892 if (!commands) {
1893 fprintf(stderr, "Cannot alloc commands\n");
1894 error_exit(ctx, 1);
1895 }
1896 reader = grn_file_reader_open(ctx, grntest_job[i].commandfile);
1897 if (!reader) {
1898 fprintf(stderr, "Cannot alloc commandfile:%s\n",
1899 grntest_job[i].commandfile);
1900 error_exit(ctx, 1);
1901 }
1902 while (grn_file_reader_read_line(ctx, reader, &line) == GRN_SUCCESS) {
1903 grn_obj *command;
1904 if (GRN_TEXT_VALUE(&line)[GRN_TEXT_LEN(&line) - 1] == '\n') {
1905 grn_bulk_truncate(ctx, &line, GRN_TEXT_LEN(&line) - 1);
1906 }
1907 if (GRN_TEXT_LEN(&line) == 0) {
1908 GRN_BULK_REWIND(&line);
1909 continue;
1910 }
1911 GRN_TEXT_PUTC(ctx, &line, '\0');
1912 if (comment_p(GRN_TEXT_VALUE(&line))) {
1913 GRN_BULK_REWIND(&line);
1914 continue;
1915 }
1916 command = grn_obj_open(ctx, GRN_BULK, 0, GRN_VOID);
1917 if (!command) {
1918 fprintf(stderr, "Cannot alloc command: %s: %s\n",
1919 grntest_job[i].commandfile, GRN_TEXT_VALUE(&line));
1920 GRN_OBJ_FIN(ctx, &line);
1921 error_exit(ctx, 1);
1922 }
1923 GRN_TEXT_SET(ctx, command, GRN_TEXT_VALUE(&line), GRN_TEXT_LEN(&line));
1924 GRN_PTR_PUT(ctx, commands, command);
1925 GRN_BULK_REWIND(&line);
1926 }
1927 grn_file_reader_close(ctx, reader);
1928 GRN_OBJ_FIN(ctx, &line);
1929 }
1930 grntest_task[tid].file = NULL;
1931 grntest_task[tid].commands = commands;
1932 grntest_task[tid].ntimes = grntest_job[i].ntimes;
1933 grntest_task[tid].jobtype = grntest_job[i].jobtype;
1934 grntest_task[tid].job_id = i;
1935 tid++;
1936 }
1937 }
1938 return tid;
1939 }
1940
1941 /*
1942 static int
1943 print_commandlist(int task_id)
1944 {
1945 int i;
1946
1947 for (i = 0; i < GRN_TEXT_LEN(grntest_task[task_id].commands); i++) {
1948 grn_obj *command;
1949 command = GRN_PTR_VALUE_AT(grntest_task[task_id].commands, i);
1950 printf("%s\n", GRN_TEXT_VALUE(command));
1951 }
1952 return 0;
1953 }
1954 */
1955
1956 /* return num of query */
1957 static int
do_jobs(grn_ctx * ctx,int jobnum,int line)1958 do_jobs(grn_ctx *ctx, int jobnum, int line)
1959 {
1960 int i, task_num, ret, qnum = 0, thread_num = 0;
1961
1962 for (i = 0; i < jobnum; i++) {
1963 /*
1964 printf("%d:type =%d:file=%s:con=%d:ntimes=%d\n", i, grntest_job[i].jobtype,
1965 grntest_job[i].commandfile, JobTable[i].concurrency, JobTable[i].ntimes);
1966
1967 */
1968 thread_num = thread_num + grntest_job[i].concurrency;
1969 }
1970
1971 if (thread_num >= MAX_CON) {
1972 fprintf(stderr, "Too many threads requested(MAX=64):line=%d\n", line);
1973 error_exit(ctx, 1);
1974 }
1975
1976 task_num = make_task_table(ctx, jobnum);
1977 if (task_num != thread_num) {
1978 fprintf(stderr, "Logical error\n");
1979 error_exit(ctx, 9);
1980 }
1981
1982 grntest_detail_on = 0;
1983 for (i = 0; i < task_num; i++) {
1984 grn_ctx_init(&grntest_ctx[i], 0);
1985 grntest_owndb[i] = NULL;
1986 if (gqtp_p(grntest_task[i].jobtype)) {
1987 ret = grn_ctx_connect(&grntest_ctx[i], grntest_serverhost, grntest_serverport, 0);
1988 if (ret) {
1989 fprintf(stderr, "Cannot connect groonga server:host=%s:port=%d:ret=%d\n",
1990 grntest_serverhost, grntest_serverport, ret);
1991 error_exit(ctx, 1);
1992 }
1993 } else if (http_p(grntest_task[i].jobtype)) {
1994 grntest_task[i].http_socket = 0;
1995 GRN_TEXT_INIT(&grntest_task[i].http_response, 0);
1996 if (grntest_owndb_mode) {
1997 grntest_owndb[i] = grn_db_open(&grntest_ctx[i], grntest_dbpath);
1998 if (grntest_owndb[i] == NULL) {
1999 fprintf(stderr, "Cannot open db:%s\n", grntest_dbpath);
2000 exit(1);
2001 }
2002 } else {
2003 grntest_owndb[i] = grn_db_create(&grntest_ctx[i], NULL, NULL);
2004 }
2005 } else {
2006 if (grntest_owndb_mode) {
2007 grntest_owndb[i] = grn_db_open(&grntest_ctx[i], grntest_dbpath);
2008 if (grntest_owndb[i] == NULL) {
2009 fprintf(stderr, "Cannot open db:%s\n", grntest_dbpath);
2010 exit(1);
2011 }
2012 }
2013 else {
2014 grn_ctx_use(&grntest_ctx[i], grntest_db);
2015 }
2016 }
2017 if (report_p(grntest_task[i].jobtype)) {
2018 grntest_detail_on++;
2019 }
2020 }
2021 if (grntest_detail_on) {
2022 if (grntest_outtype == OUT_TSV) {
2023 ;
2024 }
2025 else {
2026 fprintf(grntest_log_file, "\"detail\": [\n");
2027 }
2028 fflush(grntest_log_file);
2029 }
2030
2031 thread_main(ctx, task_num);
2032
2033 for (i = 0; i < task_num; i++) {
2034 if (grntest_owndb[i]) {
2035 grn_obj_close(&grntest_ctx[i], grntest_owndb[i]);
2036 }
2037 if (http_p(grntest_task[i].jobtype)) {
2038 GRN_OBJ_FIN(&grntest_ctx[i], &grntest_task[i].http_response);
2039 }
2040 grn_ctx_fin(&grntest_ctx[i]);
2041 qnum = qnum + grntest_task[i].qnum;
2042 }
2043
2044 i = 0;
2045 while (i < task_num) {
2046 int job_id;
2047 if (grntest_task[i].commands) {
2048 job_id = grntest_task[i].job_id;
2049 GRN_OBJ_FIN(ctx, grntest_task[i].commands);
2050 while (job_id == grntest_task[i].job_id) {
2051 i++;
2052 }
2053 } else {
2054 i++;
2055 }
2056 }
2057 for (i = 0; i < jobnum; i++) {
2058 if (grntest_job[i].outputlog) {
2059 int ret;
2060 ret = fclose(grntest_job[i].outputlog);
2061 if (ret) {
2062 fprintf(stderr, "Cannot close %s\n", grntest_job[i].logfile);
2063 exit(1);
2064 }
2065 }
2066 if (grntest_job[i].inputlog) {
2067 grn_file_reader_close(ctx, grntest_job[i].inputlog);
2068 }
2069 }
2070 return qnum;
2071 }
2072
2073 /* return num of query */
2074 static int
do_script(grn_ctx * ctx,const char * script_file_path)2075 do_script(grn_ctx *ctx, const char *script_file_path)
2076 {
2077 int n_lines = 0;
2078 int n_jobs;
2079 int n_queries, total_n_queries = 0;
2080 grn_file_reader *script_file;
2081 grn_obj line;
2082
2083 script_file = grn_file_reader_open(ctx, script_file_path);
2084 if (script_file == NULL) {
2085 fprintf(stderr, "Cannot open script file: <%s>\n", script_file_path);
2086 error_exit(ctx, 1);
2087 }
2088
2089 GRN_TEXT_INIT(&line, 0);
2090 while (grn_file_reader_read_line(ctx, script_file, &line) == GRN_SUCCESS) {
2091 if (grntest_sigint) {
2092 break;
2093 }
2094 n_lines++;
2095 grntest_jobdone = 0;
2096 n_jobs = get_jobs(ctx, GRN_TEXT_VALUE(&line), n_lines);
2097 grntest_jobnum = n_jobs;
2098
2099 if (n_jobs > 0) {
2100 GRN_TIME_INIT(&grntest_jobs_start, 0);
2101 GRN_TIME_NOW(ctx, &grntest_jobs_start);
2102 if (grntest_outtype == OUT_TSV) {
2103 fprintf(grntest_log_file, "jobs-start\t%s\n", GRN_TEXT_VALUE(&line));
2104 } else {
2105 fprintf(grntest_log_file, "{\"jobs\": \"%s\",\n", GRN_TEXT_VALUE(&line));
2106 }
2107 n_queries = do_jobs(ctx, n_jobs, n_lines);
2108 if (grntest_outtype == OUT_TSV) {
2109 fprintf(grntest_log_file, "jobs-end\t%s\n", GRN_TEXT_VALUE(&line));
2110 } else {
2111 fprintf(grntest_log_file, "},\n");
2112 }
2113 total_n_queries += n_queries;
2114
2115 grn_obj_close(ctx, &grntest_jobs_start);
2116 }
2117 if (grntest_stop_flag) {
2118 fprintf(stderr, "Error:Quit\n");
2119 break;
2120 }
2121 GRN_BULK_REWIND(&line);
2122 }
2123 grn_obj_unlink(ctx, &line);
2124
2125 grn_file_reader_close(ctx, script_file);
2126
2127 return total_n_queries;
2128 }
2129
2130 static int
start_local(grn_ctx * ctx,const char * dbpath)2131 start_local(grn_ctx *ctx, const char *dbpath)
2132 {
2133 grntest_db = grn_db_open(ctx, dbpath);
2134 if (!grntest_db) {
2135 grntest_db = grn_db_create(ctx, dbpath, NULL);
2136 }
2137 if (!grntest_db) {
2138 fprintf(stderr, "Cannot open db:%s\n", dbpath);
2139 exit(1);
2140 }
2141 return 0;
2142 }
2143
2144 static int
check_server(grn_ctx * ctx)2145 check_server(grn_ctx *ctx)
2146 {
2147 int ret, retry = 0;
2148 while (1) {
2149 ret = grn_ctx_connect(ctx, grntest_serverhost, grntest_serverport, 0);
2150 if (ret == GRN_CONNECTION_REFUSED) {
2151 grn_sleep(1);
2152 retry++;
2153 if (retry > 5) {
2154 fprintf(stderr, "Cannot connect groonga server:host=%s:port=%d:ret=%d\n",
2155 grntest_serverhost, grntest_serverport, ret);
2156 return 1;
2157 }
2158 continue;
2159 }
2160 if (ret) {
2161 fprintf(stderr, "Cannot connect groonga server:host=%s:port=%d:ret=%d\n",
2162 grntest_serverhost, grntest_serverport, ret);
2163 return 1;
2164 }
2165 break;
2166 }
2167 return 0;
2168 }
2169
2170 #define MODE_LIST 1
2171 #define MODE_GET 2
2172 #define MODE_PUT 3
2173 #define MODE_TIME 4
2174
2175 static int
check_response(char * buf)2176 check_response(char *buf)
2177 {
2178 if (buf[0] == '1') {
2179 return 1;
2180 }
2181 if (buf[0] == '2') {
2182 return 1;
2183 }
2184 if (buf[0] == '3') {
2185 return 1;
2186 }
2187 return 0;
2188 }
2189
2190 static int
read_response(socket_t socket,char * buf)2191 read_response(socket_t socket, char *buf)
2192 {
2193 int ret;
2194 ret = recv(socket, buf, BUF_LEN - 1, 0);
2195 if (ret == -1) {
2196 fprintf(stderr, "recv error:3\n");
2197 exit(1);
2198 }
2199 buf[ret] ='\0';
2200 #ifdef DEBUG_FTP
2201 fprintf(stderr, "recv:%s", buf);
2202 #endif
2203 return ret;
2204 }
2205
2206 static int
put_file(socket_t socket,const char * filename)2207 put_file(socket_t socket, const char *filename)
2208 {
2209 FILE *fp;
2210 int c, ret, size = 0;
2211 char buf[1];
2212
2213 fp = fopen(filename, "rb");
2214 if (!fp) {
2215 fprintf(stderr, "LOCAL:no such file:%s\n", filename);
2216 return 0;
2217 }
2218
2219 while ((c = fgetc(fp)) != EOF) {
2220 buf[0] = c;
2221 ret = send(socket, buf, 1, 0);
2222 if (ret == -1) {
2223 fprintf(stderr, "send error\n");
2224 exit(1);
2225 }
2226 size++;
2227 }
2228 fclose(fp);
2229 return size;
2230 }
2231
2232 static int
ftp_list(socket_t data_socket)2233 ftp_list(socket_t data_socket)
2234 {
2235 int ret;
2236 char buf[BUF_LEN];
2237
2238 while (1) {
2239 ret = recv(data_socket, buf, BUF_LEN - 2, 0);
2240 if (ret == 0) {
2241 fflush(stdout);
2242 return 0;
2243 }
2244 buf[ret] = '\0';
2245 fprintf(stdout, "%s", buf);
2246 }
2247
2248 return 0;
2249 }
2250
2251 static int
get_file(socket_t socket,const char * filename,int size)2252 get_file(socket_t socket, const char *filename, int size)
2253 {
2254 FILE *fp;
2255 int ret, total;
2256 char buf[FTPBUF];
2257
2258 fp = fopen(filename, "wb");
2259 if (!fp) {
2260 fprintf(stderr, "Cannot open %s\n", filename);
2261 return -1;
2262 }
2263
2264 total = 0;
2265 while (total != size) {
2266 ret = recv(socket, buf, FTPBUF, 0);
2267 if (ret == -1) {
2268 fprintf(stderr, "recv error:2:ret=%d:size=%d:total\n", ret, size);
2269 return -1;
2270 }
2271 if (ret == 0) {
2272 break;
2273 }
2274 fwrite(buf, ret, 1, fp);
2275 total = total + ret;
2276 }
2277
2278 fclose(fp);
2279 return size;
2280 }
2281
2282 static int
get_port(char * buf,char * host,int * port)2283 get_port(char *buf, char *host, int *port)
2284 {
2285 int ret,d1,d2,d3,d4,d5,d6;
2286 ret = sscanf(buf, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
2287 &d1, &d2, &d3, &d4, &d5, &d6);
2288 if (ret != 6) {
2289 fprintf(stderr, "Cannot enter passsive mode\n");
2290 return 0;
2291 }
2292
2293 *port = d5 * 256 + d6;
2294 sprintf(host, "%d.%d.%d.%d", d1, d2, d3, d4);
2295 return 1;
2296 }
2297
2298 static char *
get_ftp_date(char * buf)2299 get_ftp_date(char *buf)
2300 {
2301 while (*buf !=' ') {
2302 buf++;
2303 if (*buf == '\0') {
2304 return NULL;
2305 }
2306 }
2307 buf++;
2308
2309 return buf;
2310 }
2311
2312 static int
get_size(char * buf)2313 get_size(char *buf)
2314 {
2315 int size;
2316
2317 while (*buf !='(') {
2318 buf++;
2319 if (*buf == '\0') {
2320 return 0;
2321 }
2322 }
2323 buf++;
2324 size = grntest_atoi(buf, buf + strlen(buf), NULL);
2325
2326 return size;
2327 }
2328
2329 int
ftp_sub(const char * user,const char * passwd,const char * host,const char * filename,int mode,const char * cd_dirname,char * retval)2330 ftp_sub(const char *user, const char *passwd, const char *host,
2331 const char *filename, int mode,
2332 const char *cd_dirname, char *retval)
2333 {
2334 int size = 0;
2335 int status = 0;
2336 socket_t command_socket, data_socket;
2337 int data_port;
2338 char data_host[BUF_LEN];
2339 char send_mesg[BUF_LEN];
2340 char buf[BUF_LEN];
2341 #ifdef WIN32
2342 char base[BUF_LEN];
2343 char fname[BUF_LEN];
2344 char ext[BUF_LEN];
2345 #else
2346 char *base;
2347 #endif /* WIN32 */
2348
2349 #ifdef WIN32
2350 WSADATA ws;
2351
2352 WSAStartup(MAKEWORD(2,0), &ws);
2353 #endif /* WIN32 */
2354
2355 if ((filename != NULL) && (strlen(filename) >= MAX_PATH_LEN)) {
2356 fprintf(stderr, "too long filename\n");
2357 exit(1);
2358 }
2359
2360 if ((cd_dirname != NULL) && (strlen(cd_dirname) >= MAX_PATH_LEN)) {
2361 fprintf(stderr, "too long dirname\n");
2362 exit(1);
2363 }
2364
2365 command_socket = open_socket(host, 21);
2366 if (command_socket == SOCKETERROR) {
2367 return 0;
2368 }
2369
2370 read_response(command_socket, buf);
2371 if (!check_response(buf)) {
2372 goto exit;
2373 }
2374
2375 /* send username */
2376 sprintf(send_mesg, "USER %s\r\n", user);
2377 write_to_server(command_socket, send_mesg);
2378 read_response(command_socket, buf);
2379 if (!check_response(buf)) {
2380 goto exit;
2381 }
2382
2383 /* send passwd */
2384 sprintf(send_mesg, "PASS %s\r\n", passwd);
2385 write_to_server(command_socket, send_mesg);
2386 read_response(command_socket, buf);
2387 if (!check_response(buf)) {
2388 goto exit;
2389 }
2390
2391 /* send TYPE I */
2392 sprintf(send_mesg, "TYPE I\r\n");
2393 write_to_server(command_socket, send_mesg);
2394 read_response(command_socket, buf);
2395 if (!check_response(buf)) {
2396 goto exit;
2397 }
2398
2399 /* send PASV */
2400 sprintf(send_mesg, "PASV\r\n");
2401 write_to_server(command_socket, send_mesg);
2402 read_response(command_socket, buf);
2403 if (!check_response(buf)) {
2404 goto exit;
2405 }
2406
2407 if (!get_port(buf, data_host, &data_port)) {
2408 goto exit;
2409 }
2410
2411 data_socket = open_socket(data_host, data_port);
2412 if (data_socket == SOCKETERROR) {
2413 goto exit;
2414 }
2415
2416 if (cd_dirname) {
2417 sprintf(send_mesg, "CWD %s\r\n", cd_dirname);
2418 write_to_server(command_socket, send_mesg);
2419 }
2420
2421 read_response(command_socket, buf);
2422 if (!check_response(buf)) {
2423 socketclose(data_socket);
2424 goto exit;
2425 }
2426
2427 #ifdef WIN32
2428 _splitpath(filename, NULL, NULL, fname, ext);
2429 grn_strcpy(base, BUF_LEN, fname);
2430 strcat(base, ext);
2431 #else
2432 grn_strcpy(buf, BUF_LEN, filename);
2433 base = basename(buf);
2434 #endif /* WIN32 */
2435
2436 switch (mode) {
2437 case MODE_LIST:
2438 if (filename) {
2439 sprintf(send_mesg, "LIST %s\r\n", filename);
2440 } else {
2441 sprintf(send_mesg, "LIST \r\n");
2442 }
2443 write_to_server(command_socket, send_mesg);
2444 break;
2445 case MODE_PUT:
2446 sprintf(send_mesg, "STOR %s\r\n", base);
2447 write_to_server(command_socket, send_mesg);
2448 break;
2449 case MODE_GET:
2450 sprintf(send_mesg, "RETR %s\r\n", base);
2451 write_to_server(command_socket, send_mesg);
2452 break;
2453 case MODE_TIME:
2454 sprintf(send_mesg, "MDTM %s\r\n", base);
2455 write_to_server(command_socket, send_mesg);
2456 break;
2457 default:
2458 fprintf(stderr, "invalid mode\n");
2459 socketclose(data_socket);
2460 goto exit;
2461 }
2462
2463 read_response(command_socket, buf);
2464 if (!check_response(buf)) {
2465 socketclose(data_socket);
2466 goto exit;
2467 }
2468 if (!strncmp(buf, "150", 3)) {
2469 size = get_size(buf);
2470 }
2471 if (!strncmp(buf, "213", 3)) {
2472 retval[BUF_LEN-2] = '\0';
2473 grn_strcpy(retval, BUF_LEN - 2, get_ftp_date(buf));
2474 if (retval[BUF_LEN-2] != '\0' ) {
2475 fprintf(stderr, "buffer over run in ftp\n");
2476 exit(1);
2477 }
2478 }
2479
2480 switch (mode) {
2481 case MODE_LIST:
2482 ftp_list(data_socket);
2483 break;
2484 case MODE_GET:
2485 if (get_file(data_socket, filename, size) == -1) {
2486 socketclose(data_socket);
2487 goto exit;
2488 }
2489 fprintf(stderr, "get:%s\n", filename);
2490 break;
2491 case MODE_PUT:
2492 if (put_file(data_socket, filename) == -1) {
2493 socketclose(data_socket);
2494 goto exit;
2495 }
2496 fprintf(stderr, "put:%s\n", filename);
2497 break;
2498 default:
2499 break;
2500 }
2501
2502 socketclose(data_socket);
2503 if ((mode == MODE_GET) || (mode == MODE_PUT)) {
2504 read_response(command_socket, buf);
2505 }
2506 write_to_server(command_socket, "QUIT\n");
2507 status = 1;
2508 exit:
2509 socketclose(command_socket);
2510
2511 #ifdef WIN32
2512 WSACleanup();
2513 #endif
2514 return status;
2515 }
2516
2517 /*
2518 static int
2519 ftp_main(int argc, char **argv)
2520 {
2521 char val[BUF_LEN];
2522 val[0] = '\0';
2523 ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, argv[2],
2524 grntest_atoi(argv[3], argv[3] + strlen(argv[3]), NULL), argv[4], val);
2525 if (val[0] != '\0') {
2526 printf("val=%s\n", val);
2527 }
2528 return 0;
2529 }
2530 */
2531
2532 static int
get_username(char * name,int maxlen)2533 get_username(char *name, int maxlen)
2534 {
2535 char *env=NULL;
2536 grn_strcpy(name, maxlen, "nobody");
2537 #ifdef WIN32
2538 env = getenv("USERNAME");
2539 #else
2540 env = getenv("USER");
2541 #endif /* WIN32 */
2542 if (strlen(env) > maxlen) {
2543 fprintf(stderr, "too long username:%s\n", env);
2544 exit(1);
2545 }
2546 if (env) {
2547 grn_strcpy(name, maxlen, env);
2548 }
2549 return 0;
2550 }
2551
2552 static int
get_date(char * date,time_t * sec)2553 get_date(char *date, time_t *sec)
2554 {
2555 #if defined(WIN32) && !defined(__GNUC__)
2556 struct tm tmbuf;
2557 struct tm *tm = &tmbuf;
2558 localtime_s(tm, sec);
2559 #else /* defined(WIN32) && !defined(__GNUC__) */
2560 # ifdef HAVE_LOCALTIME_R
2561 struct tm result;
2562 struct tm *tm = &result;
2563 localtime_r(sec, tm);
2564 # else /* HAVE_LOCALTIME_R */
2565 struct tm *tm = localtime(sec);
2566 # endif /* HAVE_LOCALTIME_R */
2567 #endif /* defined(WIN32) && !defined(__GNUC__) */
2568
2569 #ifdef WIN32
2570 strftime(date, 128, "%Y-%m-%d %H:%M:%S", tm);
2571 #else
2572 strftime(date, 128, "%F %T", tm);
2573 #endif /* WIN32 */
2574
2575 return 1;
2576 }
2577
2578 static int
get_scriptname(const char * path,char * name,size_t name_len,const char * suffix)2579 get_scriptname(const char *path, char *name, size_t name_len, const char *suffix)
2580 {
2581 int slen = strlen(suffix);
2582 int len = strlen(path);
2583
2584 if (len >= BUF_LEN) {
2585 fprintf(stderr, "too long script name\n");
2586 exit(1);
2587 }
2588 if (slen > len) {
2589 fprintf(stderr, "too long suffux\n");
2590 exit(1);
2591 }
2592
2593 grn_strcpy(name, name_len, path);
2594 if (strncmp(&name[len-slen], suffix, slen)) {
2595 name[0] = '\0';
2596 return 0;
2597 }
2598 name[len-slen] = '\0';
2599 return 1;
2600 }
2601
2602 #ifdef WIN32
2603 static int
get_tm_from_serverdate(char * serverdate,struct tm * tm)2604 get_tm_from_serverdate(char *serverdate, struct tm *tm)
2605 {
2606 int res;
2607 int year, month, day, hour, minute, second;
2608
2609 res = sscanf(serverdate, "%4d%2d%2d%2d%2d%2d",
2610 &year, &month, &day, &hour, &minute, &second);
2611
2612 /*
2613 printf("%d %d %d %d %d %d\n", year, month, day, hour, minute, second);
2614 */
2615
2616 tm->tm_sec = second;
2617 tm->tm_min = minute;
2618 tm->tm_hour = hour;
2619 tm->tm_mday = day;
2620 tm->tm_mon = month - 1;
2621 tm->tm_year = year - 1900;
2622 tm->tm_isdst = -1;
2623
2624 return 0;
2625 }
2626 #endif /* WIN32 */
2627
2628
2629
2630 static int
sync_sub(grn_ctx * ctx,const char * filename)2631 sync_sub(grn_ctx *ctx, const char *filename)
2632 {
2633 int ret;
2634 char serverdate[BUF_LEN];
2635 #ifdef WIN32
2636 struct _stat statbuf;
2637 #else
2638 struct stat statbuf;
2639 #endif /* WIN32 */
2640 time_t st, lt;
2641 struct tm stm;
2642
2643 ret = ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, filename, MODE_TIME, "data",
2644 serverdate);
2645 if (ret == 0) {
2646 fprintf(stderr, "[%s] does not exist in server\n", filename);
2647 return 0;
2648 }
2649 #ifdef WIN32
2650 get_tm_from_serverdate(serverdate, &stm);
2651 #else
2652 strptime(serverdate, "%Y%m%d %H%M%S", &stm);
2653 #endif /* WIN32 */
2654
2655 /* fixme! needs timezone info */
2656 st = mktime(&stm) + 3600 * 9;
2657 lt = st;
2658
2659 #ifdef WIN32
2660 ret = _stat(filename, &statbuf);
2661 #else
2662 ret = stat(filename, &statbuf);
2663 #endif /* WIN32 */
2664
2665 if (!ret) {
2666 lt = statbuf.st_mtime;
2667 if (lt < st) {
2668 fprintf(stderr, "newer [%s] exists in server\n", filename);
2669 fflush(stderr);
2670 ret = ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, filename, MODE_GET, "data",
2671 NULL);
2672 return ret;
2673 }
2674 } else {
2675 fprintf(stderr, "[%s] does not exist in local\n", filename);
2676 fflush(stderr);
2677 ret = ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, filename, MODE_GET, "data",
2678 NULL);
2679 return ret;
2680 }
2681 return 0;
2682 }
2683
2684 static int
cache_file(grn_ctx * ctx,char ** flist,char * file,int fnum)2685 cache_file(grn_ctx *ctx, char **flist, char *file, int fnum)
2686 {
2687 int i;
2688
2689 for (i = 0; i < fnum; i++) {
2690 if (!strcmp(flist[i], file) ) {
2691 return fnum;
2692 }
2693 }
2694 flist[fnum] = GRN_STRDUP(file);
2695 fnum++;
2696 if (fnum >= BUF_LEN) {
2697 fprintf(stderr, "too many uniq commands file!\n");
2698 exit(1);
2699 }
2700 return fnum;
2701 }
2702
2703 static int
sync_datafile(grn_ctx * ctx,const char * script_file_path)2704 sync_datafile(grn_ctx *ctx, const char *script_file_path)
2705 {
2706 int line = 0;
2707 int fnum = 0;
2708 int i, job_num;
2709 FILE *fp;
2710 char buf[BUF_LEN];
2711 char *filelist[BUF_LEN];
2712
2713 fp = fopen(script_file_path, "r");
2714 if (fp == NULL) {
2715 fprintf(stderr, "Cannot open script file: <%s>\n", script_file_path);
2716 error_exit(ctx, 1);
2717 }
2718 buf[BUF_LEN-2] = '\0';
2719 while (fgets(buf, BUF_LEN, fp) != NULL) {
2720 line++;
2721 if (buf[BUF_LEN-2] != '\0') {
2722 fprintf(stderr, "Too long line in script file:%d\n", line);
2723 error_exit(ctx, 1);
2724 }
2725 job_num = get_jobs(ctx, buf, line);
2726
2727 if (job_num > 0) {
2728 for (i = 0; i < job_num; i++) {
2729 /*
2730 printf("commandfile=[%s]:buf=%s\n", grntest_job[i].commandfile, buf);
2731 */
2732 fnum = cache_file(ctx, filelist, grntest_job[i].commandfile, fnum);
2733 }
2734 }
2735 }
2736 for (i = 0; i < fnum; i++) {
2737 if (sync_sub(ctx, filelist[i])) {
2738 fprintf(stderr, "updated!:%s\n", filelist[i]);
2739 fflush(stderr);
2740 }
2741 GRN_FREE(filelist[i]);
2742 }
2743 fclose(fp);
2744 return fnum;
2745 }
2746
2747 static int
sync_script(grn_ctx * ctx,const char * filename)2748 sync_script(grn_ctx *ctx, const char *filename)
2749 {
2750 int ret, filenum;
2751
2752 ret = sync_sub(ctx, filename);
2753 if (!ret) {
2754 return 0;
2755 }
2756
2757 fprintf(stderr, "updated!:%s\n", filename);
2758 fflush(stderr);
2759 filenum = sync_datafile(ctx, filename);
2760 return 1;
2761 }
2762
2763 static void
usage(void)2764 usage(void)
2765 {
2766 fprintf(stderr,
2767 "Usage: grntest [options...] [script] [db]\n"
2768 "options:\n"
2769 " --dir: show script files on ftp server\n"
2770 " -i, --host <ip/hostname>: server address to listen (default: %s)\n"
2771 " --localonly: omit server connection\n"
2772 " --log-output-dir: specify output dir (default: current)\n"
2773 " --ftp: connect to ftp server\n"
2774 " --onmemory: load all commands into memory\n"
2775 " --output-type <tsv/json>: specify output-type (default: json)\n"
2776 " --owndb: open dbs for each ctx\n"
2777 " -p, --port <port number>: server port number (default: %d)\n"
2778 " --groonga <groonga_path>: groonga command path (default: %s)\n"
2779 " --protocol <gqtp|http>: groonga server protocol (default: %s)\n"
2780 " --log-path <path>: specify log file path\n"
2781 " --pid-path <path>: specify file path to store PID file\n",
2782 DEFAULT_DEST, DEFAULT_PORT,
2783 groonga_path, groonga_protocol);
2784 exit(1);
2785 }
2786
2787 enum {
2788 mode_default = 0,
2789 mode_list,
2790 mode_usage,
2791 };
2792
2793 #define MODE_MASK 0x007f
2794 #define MODE_FTP 0x0080
2795 #define MODE_LOCALONLY 0x0100
2796 #define MODE_OWNDB 0x0800
2797 #define MODE_ONMEMORY 0x1000
2798
2799
2800 static int
get_token(char * line,char * token,int maxlen,char ** next)2801 get_token(char *line, char *token, int maxlen, char **next)
2802 {
2803 int i = 0;
2804
2805 *next = NULL;
2806 token[i] = '\0';
2807
2808 while (*line) {
2809 if (grn_isspace(line, GRN_ENC_UTF8) == 1) {
2810 line++;
2811 continue;
2812 }
2813 if (*line == ';') {
2814 token[0] = ';';
2815 token[1] = '\0';
2816 *next = line + 1;
2817 return 1;
2818 }
2819 if (*line == '#') {
2820 token[0] = ';';
2821 token[1] = '\0';
2822 *next = line + 1;
2823 return 1;
2824 }
2825 break;
2826 }
2827
2828 while (*line) {
2829 token[i] = *line;
2830 i++;
2831 if (grn_isspace(line + 1, GRN_ENC_UTF8) == 1) {
2832 token[i] = '\0';
2833 *next = line + 1;
2834 return 1;
2835 }
2836 if (*(line + 1) == ';') {
2837 token[i] = '\0';
2838 *next = line + 1;
2839 return 1;
2840 }
2841 if (*(line + 1) == '#') {
2842 token[i] = '\0';
2843 *next = line + 1;
2844 return 1;
2845 }
2846 if (*(line + 1) == '\0') {
2847 token[i] = '\0';
2848 return 1;
2849 }
2850
2851 line++;
2852 }
2853 return 0;
2854 }
2855
2856 /* SET_PORT and SET_HOST */
2857 static grn_bool
check_script(grn_ctx * ctx,const char * script_file_path)2858 check_script(grn_ctx *ctx, const char *script_file_path)
2859 {
2860 grn_file_reader *script_file;
2861 grn_obj line;
2862 char token[BUF_LEN];
2863 char prev[BUF_LEN];
2864 char *next = NULL;
2865
2866 script_file = grn_file_reader_open(ctx, script_file_path);
2867 if (!script_file) {
2868 fprintf(stderr, "Cannot open script file: <%s>\n", script_file_path);
2869 return GRN_FALSE;
2870 }
2871
2872 GRN_TEXT_INIT(&line, 0);
2873 while (grn_file_reader_read_line(ctx, script_file, &line) == GRN_SUCCESS) {
2874 GRN_TEXT_VALUE(&line)[GRN_TEXT_LEN(&line) - 1] = '\0';
2875 get_token(GRN_TEXT_VALUE(&line), token, BUF_LEN, &next);
2876 grn_strcpy(prev, BUF_LEN, token);
2877
2878 while (next) {
2879 get_token(next, token, BUF_LEN, &next);
2880 if (!strncmp(prev, "SET_PORT", 8)) {
2881 grntest_serverport = grn_atoi(token, token + strlen(token), NULL);
2882 }
2883 if (!strncmp(prev, "SET_HOST", 8)) {
2884 grn_strcpy(grntest_serverhost, BUF_LEN, token);
2885 grntest_remote_mode = 1;
2886 }
2887 grn_strcpy(prev, BUF_LEN, token);
2888 }
2889 }
2890 grn_obj_unlink(ctx, &line);
2891
2892 grn_file_reader_close(ctx, script_file);
2893 return GRN_TRUE;
2894 }
2895
2896 #ifndef WIN32
2897 static void
timeout(int sig)2898 timeout(int sig)
2899 {
2900 fprintf(stderr, "timeout:groonga server cannot shutdown!!\n");
2901 fprintf(stderr, "Use \"kill -9 %d\"\n", grntest_server_id);
2902 alarm(0);
2903 }
2904
2905 static void
setexit(int sig)2906 setexit(int sig)
2907 {
2908 grntest_sigint = 1;
2909 }
2910
2911 static int
setsigalarm(int sec)2912 setsigalarm(int sec)
2913 {
2914 int ret;
2915 struct sigaction sig;
2916
2917 alarm(sec);
2918 sig.sa_handler = timeout;
2919 sig.sa_flags = 0;
2920 sigemptyset(&sig.sa_mask);
2921 ret = sigaction(SIGALRM, &sig, NULL);
2922 if (ret == -1) {
2923 fprintf(stderr, "setsigalarm:errno= %d\n", errno);
2924 }
2925 return ret;
2926 }
2927
2928 static int
setsigint(void)2929 setsigint(void)
2930 {
2931 int ret;
2932 struct sigaction sig;
2933
2934 sig.sa_handler = setexit;
2935 sig.sa_flags = 0;
2936 sigemptyset(&sig.sa_mask);
2937 ret = sigaction(SIGINT, &sig, NULL);
2938 if (ret == -1) {
2939 fprintf(stderr, "setsigint:errno= %d\n", errno);
2940 }
2941 return ret;
2942 }
2943 #endif /* WIN32 */
2944
2945 int
main(int argc,char ** argv)2946 main(int argc, char **argv)
2947 {
2948 int qnum, i, mode = 0;
2949 int exit_code = EXIT_SUCCESS;
2950 grn_ctx context;
2951 char sysinfo[BUF_LEN];
2952 char log_path_buffer[BUF_LEN];
2953 const char *log_path = NULL;
2954 const char *pid_path = NULL;
2955 const char *portstr = NULL, *hoststr = NULL, *dbname = NULL, *scrname = NULL, *outdir = NULL, *outtype = NULL;
2956 time_t sec;
2957
2958 static grn_str_getopt_opt opts[] = {
2959 {'i', "host", NULL, 0, GETOPT_OP_NONE},
2960 {'p', "port", NULL, 0, GETOPT_OP_NONE},
2961 {'\0', "log-output-dir", NULL, 0, GETOPT_OP_NONE},
2962 {'\0', "output-type", NULL, 0, GETOPT_OP_NONE},
2963 {'\0', "dir", NULL, mode_list, GETOPT_OP_UPDATE},
2964 {'\0', "ftp", NULL, MODE_FTP, GETOPT_OP_ON},
2965 {'h', "help", NULL, mode_usage, GETOPT_OP_UPDATE},
2966 {'\0', "localonly", NULL, MODE_LOCALONLY, GETOPT_OP_ON},
2967 {'\0', "onmemory", NULL, MODE_ONMEMORY, GETOPT_OP_ON},
2968 {'\0', "owndb", NULL, MODE_OWNDB, GETOPT_OP_ON},
2969 {'\0', "groonga", NULL, 0, GETOPT_OP_NONE},
2970 {'\0', "protocol", NULL, 0, GETOPT_OP_NONE},
2971 {'\0', "log-path", NULL, 0, GETOPT_OP_NONE},
2972 {'\0', "pid-path", NULL, 0, GETOPT_OP_NONE},
2973 {'\0', NULL, NULL, 0, 0}
2974 };
2975
2976 opts[0].arg = &hoststr;
2977 opts[1].arg = &portstr;
2978 opts[2].arg = &outdir;
2979 opts[3].arg = &outtype;
2980 opts[10].arg = &groonga_path;
2981 opts[11].arg = &groonga_protocol;
2982 opts[12].arg = &log_path;
2983 opts[13].arg = &pid_path;
2984
2985 i = grn_str_getopt(argc, argv, opts, &mode);
2986 if (i < 0) {
2987 usage();
2988 }
2989
2990 switch (mode & MODE_MASK) {
2991 case mode_list :
2992 ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, "*.scr", 1, "data",
2993 NULL);
2994 return 0;
2995 break;
2996 case mode_usage :
2997 usage();
2998 break;
2999 default :
3000 break;
3001 }
3002
3003 if (pid_path) {
3004 FILE *pid_file;
3005 pid_file = fopen(pid_path, "w");
3006 if (pid_file) {
3007 fprintf(pid_file, "%d", grn_getpid());
3008 fclose(pid_file);
3009 } else {
3010 fprintf(stderr,
3011 "failed to open PID file: <%s>: %s\n",
3012 pid_path, strerror(errno));
3013 }
3014 }
3015
3016 if (i < argc) {
3017 scrname = argv[i];
3018 }
3019 if (i < argc - 1) {
3020 dbname = argv[i+1];
3021 }
3022 grntest_dbpath = dbname;
3023
3024 if (mode & MODE_LOCALONLY) {
3025 grntest_localonly_mode = 1;
3026 grntest_remote_mode = 1;
3027 }
3028
3029 if (mode & MODE_OWNDB) {
3030 grntest_localonly_mode = 1;
3031 grntest_remote_mode = 1;
3032 grntest_owndb_mode = 1;
3033 }
3034
3035 if (mode & MODE_ONMEMORY) {
3036 grntest_onmemory_mode= 1;
3037 }
3038
3039 if (mode & MODE_FTP) {
3040 grntest_ftp_mode = GRN_TRUE;
3041 }
3042
3043 if ((scrname == NULL) || (dbname == NULL)) {
3044 usage();
3045 }
3046
3047 grn_strcpy(grntest_serverhost, BUF_LEN, DEFAULT_DEST);
3048 if (hoststr) {
3049 grntest_remote_mode = 1;
3050 grn_strcpy(grntest_serverhost, BUF_LEN, hoststr);
3051 }
3052 grntest_serverport = DEFAULT_PORT;
3053 if (portstr) {
3054 grntest_serverport = grn_atoi(portstr, portstr + strlen(portstr), NULL);
3055 }
3056
3057 if (outtype && !strcmp(outtype, "tsv")) {
3058 grntest_outtype = OUT_TSV;
3059 }
3060
3061 grn_default_logger_set_path(GRN_LOG_PATH);
3062
3063 grn_init();
3064 CRITICAL_SECTION_INIT(grntest_cs);
3065
3066 grn_ctx_init(&context, 0);
3067 grn_ctx_init(&grntest_server_context, 0);
3068 grn_db_create(&grntest_server_context, NULL, NULL);
3069 grn_set_default_encoding(GRN_ENC_UTF8);
3070
3071 if (grntest_ftp_mode) {
3072 sync_script(&context, scrname);
3073 }
3074 if (!check_script(&context, scrname)) {
3075 exit_code = EXIT_FAILURE;
3076 goto exit;
3077 }
3078
3079 start_local(&context, dbname);
3080 if (!grntest_remote_mode) {
3081 start_server(dbname, 0);
3082 }
3083
3084 if (!grntest_localonly_mode) {
3085 if (check_server(&grntest_server_context)) {
3086 goto exit;
3087 }
3088 }
3089
3090 get_scriptname(scrname, grntest_scriptname, BUF_LEN, ".scr");
3091 get_username(grntest_username, 256);
3092
3093 GRN_TIME_INIT(&grntest_starttime, 0);
3094 GRN_TIME_NOW(&context, &grntest_starttime);
3095 sec = (time_t)(GRN_TIME_VALUE(&grntest_starttime)/1000000);
3096 get_date(grntest_date, &sec);
3097
3098 if (!log_path) {
3099 if (outdir) {
3100 sprintf(log_path_buffer,
3101 "%s/%s-%s-%" GRN_FMT_LLD "-%s.log", outdir, grntest_scriptname,
3102 grntest_username,
3103 GRN_TIME_VALUE(&grntest_starttime), grn_get_version());
3104 } else {
3105 sprintf(log_path_buffer,
3106 "%s-%s-%" GRN_FMT_LLD "-%s.log", grntest_scriptname,
3107 grntest_username,
3108 GRN_TIME_VALUE(&grntest_starttime), grn_get_version());
3109 }
3110 log_path = log_path_buffer;
3111 }
3112
3113 grntest_log_file = fopen(log_path, "w+b");
3114 if (!grntest_log_file) {
3115 fprintf(stderr, "Cannot open log file: <%s>\n", log_path);
3116 goto exit;
3117 }
3118
3119 get_sysinfo(dbname, sysinfo, BUF_LEN);
3120 output_sysinfo(sysinfo);
3121
3122 #ifndef WIN32
3123 setsigint();
3124 #endif /* WIN32 */
3125 qnum = do_script(&context, scrname);
3126 output_result_final(&context, qnum);
3127 fclose(grntest_log_file);
3128
3129 if (grntest_ftp_mode) {
3130 ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, log_path, 3,
3131 "report", NULL);
3132 }
3133 fprintf(stderr, "grntest done. logfile=%s\n", log_path);
3134
3135 exit:
3136 if (pid_path) {
3137 remove(pid_path);
3138 }
3139
3140 shutdown_server();
3141 #ifdef WIN32
3142 if (!grntest_remote_mode) {
3143 int ret;
3144 ret = WaitForSingleObject(grntest_pi.hProcess, 20000);
3145 if (ret == WAIT_TIMEOUT) {
3146 fprintf(stderr, "timeout:groonga server cannot shutdown!!\n");
3147 fprintf(stderr, "Cannot wait\n");
3148 exit(1);
3149 }
3150 }
3151 #else
3152 if (grntest_server_id) {
3153 int ret, pstatus;
3154 setsigalarm(20);
3155 ret = waitpid(grntest_server_id, &pstatus, 0);
3156 if (ret < 0) {
3157 fprintf(stderr, "Cannot wait\n");
3158 exit(1);
3159 }
3160 /*
3161 else {
3162 fprintf(stderr, "pstatus = %d\n", pstatus);
3163 }
3164 */
3165 alarm(0);
3166 }
3167 #endif /* WIN32 */
3168 CRITICAL_SECTION_FIN(grntest_cs);
3169 grn_obj_close(&context, &grntest_starttime);
3170 grn_obj_close(&context, grntest_db);
3171 grn_ctx_fin(&context);
3172 grn_obj_close(&grntest_server_context, grn_ctx_db(&grntest_server_context));
3173 grn_ctx_fin(&grntest_server_context);
3174 grn_fin();
3175 return exit_code;
3176 }
3177