Advertisement
Guest User

Untitled

a guest
Dec 6th, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.68 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdbool.h>
  4. #include <mysql/mysql.h>
  5. #include <event.h>
  6.  
  7. static const char *CONFIG_HOST = "localhost";
  8. static const char *CONFIG_USER = "root";
  9. static const char *CONFIG_PASSWORD = "***";
  10. static const char *CONFIG_DATABASE = "***";
  11. static const int CONFIG_NUM_CONNECTIONS = 10;
  12.  
  13. enum mysql_connection_state {
  14. CONNECT_START,
  15. CONNECT_WAITING,
  16. CONNECT_DONE,
  17.  
  18. QUERY_START,
  19. QUERY_WAITING,
  20. QUERY_RESULT_READY,
  21.  
  22. FETCH_ROW_START,
  23. FETCH_ROW_WAITING,
  24. FETCH_ROW_RESULT_READY,
  25.  
  26. CLOSE_START,
  27. CLOSE_WAITING,
  28. CLOSE_DONE
  29. };
  30.  
  31. struct mysql_connection {
  32. enum mysql_connection_state state;
  33. MYSQL mysql;
  34. MYSQL *ret;
  35. MYSQL_RES *result;
  36. MYSQL_ROW row;
  37. struct event mysql_event;
  38. struct query_entry *current_query_entry;
  39. int err;
  40. int index;
  41. };
  42.  
  43. struct query_entry {
  44. struct query_entry *next;
  45. char *query;
  46. int index;
  47. };
  48.  
  49. static struct query_entry *g_query_list;
  50. static struct query_entry **g_tail_ptr = &g_query_list;
  51. static int g_active_connection_num = 0;
  52. static int g_query_counter = 0;
  53.  
  54. static void connection_state_loop(int fd, short event, void *data);
  55.  
  56. static void fatal(struct mysql_connection *conn, const char *msg) {
  57. fprintf(stderr, "%s: %s\n", msg, (conn ? mysql_error(&conn->mysql) : ""));
  58. exit(1);
  59. }
  60.  
  61. static inline int add_event(int status, struct mysql_connection *conn) {
  62. short wait_event= 0;
  63. if (status & MYSQL_WAIT_READ) {
  64. wait_event|= EV_READ;
  65. }
  66. if (status & MYSQL_WAIT_WRITE) {
  67. wait_event|= EV_WRITE;
  68. }
  69.  
  70. int fd = -1;
  71. if (wait_event) {
  72. fd = mysql_get_socket(&conn->mysql);
  73. }
  74.  
  75. struct timeval tv, *ptv = NULL;
  76. if (status & MYSQL_WAIT_TIMEOUT) {
  77. tv.tv_sec = mysql_get_timeout_value(&conn->mysql);
  78. tv.tv_usec = 0;
  79. ptv = &tv;
  80. }
  81.  
  82. event_set(&conn->mysql_event, fd, wait_event, connection_state_loop, conn);
  83. event_add(&conn->mysql_event, ptv);
  84.  
  85. return 0;
  86. }
  87.  
  88. static int mysql_status(short event) {
  89. int status= 0;
  90. if (event & EV_READ) {
  91. status |= MYSQL_WAIT_READ;
  92. }
  93. if (event & EV_WRITE) {
  94. status |= MYSQL_WAIT_WRITE;
  95. }
  96. if (event & EV_TIMEOUT) {
  97. status |= MYSQL_WAIT_TIMEOUT;
  98. }
  99.  
  100. return status;
  101. }
  102.  
  103. static int connection_decide_next_state(int need_wait, struct mysql_connection *connection, int state_wait, int state_go_on) {
  104. if (need_wait) {
  105. connection->state = state_wait;
  106. add_event(need_wait, connection);
  107. return 0;
  108. } else {
  109. connection->state = state_go_on;
  110. return 1;
  111. }
  112. }
  113.  
  114. static bool connection_state_run(struct mysql_connection *connection, short event) {
  115. bool running = true;
  116. switch (connection->state) {
  117. int status;
  118. case CONNECT_START:
  119. status = mysql_real_connect_start(&connection->ret, &connection->mysql, CONFIG_HOST, CONFIG_USER, CONFIG_PASSWORD, CONFIG_DATABASE, 0, NULL, 0);
  120. running = connection_decide_next_state(status, connection, CONNECT_WAITING, CONNECT_DONE);
  121. break;
  122.  
  123. case CONNECT_WAITING:
  124. status = mysql_real_connect_cont(&connection->ret, &connection->mysql, mysql_status(event));
  125. running = connection_decide_next_state(status, connection, CONNECT_WAITING, CONNECT_DONE);
  126. break;
  127.  
  128. case CONNECT_DONE:
  129. if (!connection->ret) {
  130. fatal(connection, "Failed to mysql_real_connect()");
  131. }
  132. connection->state = QUERY_START;
  133. break;
  134.  
  135. case QUERY_START:
  136. connection->current_query_entry = g_query_list;
  137. if (!connection->current_query_entry) {
  138. connection->state = CLOSE_START;
  139. break;
  140. }
  141. g_query_list = g_query_list->next;
  142. status= mysql_real_query_start(&connection->err, &connection->mysql, connection->current_query_entry->query, strlen(connection->current_query_entry->query));
  143. running = connection_decide_next_state(status, connection, QUERY_WAITING, QUERY_RESULT_READY);
  144. break;
  145.  
  146. case QUERY_WAITING:
  147. status = mysql_real_query_cont(&connection->err, &connection->mysql, mysql_status(event));
  148. running = connection_decide_next_state(status, connection, QUERY_WAITING, QUERY_RESULT_READY);
  149. break;
  150.  
  151. case QUERY_RESULT_READY:
  152. if (connection->err) {
  153. printf("%d | Error: %s\n", connection->index, mysql_error(&connection->mysql));
  154. connection->state = CONNECT_DONE;
  155. break;
  156. }
  157. free(connection->current_query_entry->query);
  158. free(connection->current_query_entry);
  159. connection->result = mysql_use_result(&connection->mysql);
  160. connection->state = (connection->result) ? FETCH_ROW_START : QUERY_START;
  161. break;
  162.  
  163. case FETCH_ROW_START:
  164. status = mysql_fetch_row_start(&connection->row, connection->result);
  165. running = connection_decide_next_state(status, connection, FETCH_ROW_WAITING, FETCH_ROW_RESULT_READY);
  166. break;
  167.  
  168. case FETCH_ROW_WAITING:
  169. status= mysql_fetch_row_cont(&connection->row, connection->result, mysql_status(event));
  170. running = connection_decide_next_state(status, connection, FETCH_ROW_WAITING, FETCH_ROW_RESULT_READY);
  171. break;
  172.  
  173. case FETCH_ROW_RESULT_READY:
  174. if (!connection->row) {
  175. if (mysql_errno(&connection->mysql)) {
  176. printf("%d | Error: %s\n", connection->index, mysql_error(&connection->mysql));
  177. } else {
  178. // EOF. No more rows
  179. }
  180. mysql_free_result(connection->result);
  181. connection->state = QUERY_START;
  182. break;
  183. }
  184.  
  185. /*
  186. // print fields in the row
  187. printf("%d %d", connection->index, connection->current_query_entry->index);
  188. for (int i= 0; i < mysql_num_fields(connection->result); i++) {
  189. printf("%s%s", (i ? "\t" : ""), (connection->row[i] ? connection->row[i] : "(null)"));
  190. }
  191. printf("\n");
  192. */
  193.  
  194. connection->state = FETCH_ROW_START;
  195. break;
  196.  
  197. case CLOSE_START:
  198. status = mysql_close_start(&connection->mysql);
  199. running = connection_decide_next_state(status, connection, CLOSE_WAITING, CLOSE_DONE);
  200. break;
  201.  
  202. case CLOSE_WAITING:
  203. status= mysql_close_cont(&connection->mysql, mysql_status(event));
  204. running = connection_decide_next_state(status, connection, CLOSE_WAITING, CLOSE_DONE);
  205. break;
  206.  
  207. case CLOSE_DONE:
  208. g_active_connection_num--;
  209. if (g_active_connection_num == 0) {
  210. event_loopbreak();
  211. }
  212. running = false;
  213. break;
  214.  
  215. default:
  216. abort();
  217. break;
  218. }
  219.  
  220. return running;
  221. }
  222.  
  223. static void connection_state_loop(int fd , short event, void *data) {
  224. while (connection_state_run((struct mysql_connection *)data, event));
  225. }
  226.  
  227. void add_query(const char *query) {
  228. struct query_entry *entry = (struct query_entry *)malloc(sizeof(*entry));
  229. if (!entry) {
  230. fatal(NULL, "Out of memory");
  231. }
  232. entry->query = (char *)malloc(strlen(query) + 1);
  233. if (!entry->query) {
  234. fatal(NULL, "Out of memory");
  235. }
  236.  
  237. strcpy(entry->query, query);
  238. entry->next = NULL;
  239. entry->index = g_query_counter++;
  240. *g_tail_ptr = entry;
  241. g_tail_ptr = &entry->next;
  242. }
  243.  
  244.  
  245. int main(int argc, char *argv[]) {
  246. struct mysql_connection *connections = (struct mysql_connection *)calloc(CONFIG_NUM_CONNECTIONS, sizeof(*connections));
  247. if (!connections) {
  248. fatal(NULL, "Out of memory");
  249. }
  250.  
  251. struct event_base *libevent_base = event_init();
  252.  
  253. for (int i = 0; i < CONFIG_NUM_CONNECTIONS; i++) {
  254. mysql_init(&connections[i].mysql);
  255. mysql_options(&connections[i].mysql, MYSQL_OPT_NONBLOCK, NULL);
  256. //mysql_options(&connections[i].mysql, MYSQL_READ_DEFAULT_GROUP, "async_queries");
  257.  
  258. connections[i].state = CONNECT_START;
  259. connections[i].index = i;
  260. g_active_connection_num++;
  261. connection_state_loop(-1, -1, &connections[i]);
  262. }
  263.  
  264. for (int i = 0; i < 10000; i++) {
  265. add_query("SELECT * FROM bans;");
  266. }
  267.  
  268. event_dispatch();
  269.  
  270. free(connections);
  271. event_base_free(libevent_base);
  272.  
  273. return 0;
  274. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement