PageRenderTime 69ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/src/grntest.c

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